//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES OR INDEMNITIES.
//
//
// (C) Copyright 2006 Marvell International Ltd.
// All Rights Reserved
//
/*++


THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.

Module Name: 

        usb20fn.cpp

Abstract:

        PXA USB Function Driver.

--*/
//#define DEBUG

#include <windows.h>
#include <ceddk.h>
#include <ddkreg.h>
#include <nkintr.h> // needed for SYSINTR_NOP
#include <pm.h>

#include "usb20fn.h"



#include "xllp_defs.h"
#include "xllp_clkmgr.h"

#include "xllp_dmac.h"
#include "xllp_udc.h"

#include "monahans_base_regs.h"
#include "monahans.h"
#include <Windev.h>


#include "UsbOTG.h"

#include "UsbIoctrl.h"
#include <clkmgr.h>

void EdbgOutputDebugString (LPCSTR sz, ...);


#define ENABLE_SERIAL_AUTO_CONNECTION

#ifdef DEBUG
void DumpData(unsigned char * buff, int len)
{
    DEBUGMSG(ZONE_TRANSFER,(_T("DATA:\r\n")));

    TCHAR oneline[256];

    while(len)
    {   
        memset(oneline, 0, sizeof(oneline));
        for(int i=0;i<16;i++)
        {
            unsigned char c=*buff;
            c>>=4;
            if(c>=10)
            {
                oneline[3*i] = c-10+_T('A');

            }else
            {
                oneline[3*i] = c+_T('0');

            }   
            c=*buff;
            c&=0xF;
            if(c>=10)
            {
                oneline[3*i+1] = c-10+_T('A');

            }else
            {
                oneline[3*i+1] = c+_T('0');

            }
            oneline[3*i+2]=_T(' '); 
            
            len--;
            buff++;
            if(len == 0)
                break;
        }
        
        
        DEBUGMSG(ZONE_DATA,(oneline) ); 
        DEBUGMSG(ZONE_DATA,(_T("\r\n") ));  
        //RETAILMSG(1,(oneline));
        
    }
    

}
void USB20Endpoint::DumpDescript()
{

    DEBUGMSG(ZONE_TRANSFER,(_T("DMA Descript:\r\n")));
    XLLP_DMAC_DESCRIPTOR_T *pDesc=(XLLP_DMAC_DESCRIPTOR_T *)m_vDesc;
    while(1)
    {
        DEBUGMSG(ZONE_DATA,(_T(" Descriptor     0x%X :\r\n"),pDesc->ddadr));
        DEBUGMSG(ZONE_DATA,(_T(" Source Address 0x%X :\r\n"),pDesc->dsadr));
        DEBUGMSG(ZONE_DATA,(_T(" Target Address 0x%X :\r\n"),pDesc->dtadr));
        DEBUGMSG(ZONE_DATA,(_T(" Command        0x%X :\r\n"),pDesc->dcmd));

        if((pDesc->ddadr&XLLP_DMAC_DDADR_STOP))
            break;
        pDesc++;
    }
    
}
#endif

VOID USB20Device::WriteULPIReg(BYTE reg, BYTE value)
{
    m_pRegsBase->u2dotgucr = (0x1U<<25)|(reg<<16) |(value<<8);

	int count = 0;
    while(m_pRegsBase->u2dotgucr & (0x1U<<25))
	{
		count++;
        Sleep(10);

		if(count > 500)
			break;
	}
}

BOOL USB20Endpoint::Init (PUSB_ENDPOINT_DESCRIPTOR pEndpointDesc,
            BYTE bConfigurationValue, BYTE bInterfaceNumber, BYTE bAlternateSetting)
{

    SETFNAME();
    FUNCTION_ENTER_MSG();
    BOOL bReturn = FALSE;
    Lock();
    
    DEBUGMSG(ZONE_FUNCTION, (_T("Enter.EP%d Init\r\n"),m_dwEndpointIndex));
    
    m_bConfigurationValue= bConfigurationValue;
    m_bInterfaceNumber = bInterfaceNumber;
    m_bAlternateSetting =bAlternateSetting;
    m_fZeroPacket = FALSE;
    m_fStalled = FALSE;
    // Change address according
    
    if ( pEndpointDesc && m_pUsbDevice!=NULL && m_dwEndpointIndex < XLLP_U2D_USB_MAX_EP_NUM) 
    {
        pEndpointDesc->bEndpointAddress = (UCHAR)((pEndpointDesc->bEndpointAddress & 0x80) | m_dwEndpointIndex);
        m_epDesc = *pEndpointDesc;
        bReturn = ReInit();
    }


    Unlock();
    FUNCTION_LEAVE_MSG();
    return bReturn;
}
BOOL   USB20Endpoint::ReInit()
{
    SETFNAME();
    FUNCTION_ENTER_MSG();
    BOOL bReturn = TRUE;
    XLLP_U2D_EP_CONFIG Config;
    
    DEBUGMSG(ZONE_FUNCTION, (_T("Enter.EP%d ReInit\r\n"),m_dwEndpointIndex));
    
    Config.ET = (XLLP_UDC_EP_TYPE_T) (m_epDesc.bmAttributes & 0x3);
    Config.ED = ((m_epDesc.bEndpointAddress & 0x80)!=0?XLLP_USB_IN:XLLP_USB_OUT);
    Config.EN = m_epDesc.bEndpointAddress & 0xf;
    Config.CN = (m_bConfigurationValue & 3);
    Config.InterfaceNumber = (m_bInterfaceNumber & 0x7);
    Config.AISN = m_bAlternateSetting & 0x7;
    if((m_pUsbDevice->m_pRegsBase->u2dctrl & XLLP_U2DCR_HS) && (Config.ET == 2))
        Config.MPS = 512;
    else
        Config.MPS = m_epDesc.wMaxPacketSize & 0x3ff ;
    Config.HBW = 0;
    Config.bufferSize = (Config.MPS+8)*2;
    
    Config.vDmaDescriptor = m_vDesc;
    Config.pDmaDescriptor = m_phyDesc;
    Config.nDescriptors=USB20_DESCRIPTORS_MAX;
                        

    if( XllpU2DEndpointSetConfig(m_pUsbDevice->GetXllpHandle(), m_dwEndpointIndex, &Config) )
    {
        bReturn = FALSE;
    }

    if( XllpU2DEndpointSetInfo(m_pUsbDevice->GetXllpHandle(), m_dwEndpointIndex, &Config) )
    {
        bReturn = FALSE;
    }
    
    XllpU2DDisableInterrupt(m_pUsbDevice->GetXllpHandle(), 
                            (XLLP_U2D_INTERRUPTS_T)m_dwEndpointIndex, 
                            (XLLP_U2D_EP_INTERRUPT_TYPE_T)(U2D_SHORT_PACKET_COMPL_INT|U2D_PACKET_COMPL_INT|U2D_FIFO_ERROR_INT|U2D_DMA_STOP)
                            );

    FUNCTION_LEAVE_MSG();
    return TRUE;
}
DWORD USB20Endpoint::StallEndpoint()
{
    SETFNAME();
    FUNCTION_ENTER_MSG();
    Lock();
    XllpU2DForceEndpointStall(m_pUsbDevice->GetXllpHandle(), m_dwEndpointIndex);
    m_fStalled = TRUE;
    Unlock();
    FUNCTION_LEAVE_MSG();
    return ERROR_SUCCESS;
}
DWORD USB20Endpoint::ClearEndpointStall()
{
    Lock();
    m_fStalled = FALSE;
    Unlock();
    return ERROR_SUCCESS;
}
DWORD USB20Endpoint::ResetEndpoint()
{
    SETFNAME();
    FUNCTION_ENTER_MSG();
    DEBUGMSG(ZONE_WARNING, (_T("ResetEndpoint+ (%d) UDCCSR =0x%x UDCCRAX = 0x%x"),
        m_dwEndpointIndex,
        m_pU2DRegsBase->u2dcsr[m_dwEndpointIndex],
        m_pU2DRegsBase->u2dcr[m_dwEndpointIndex]));
    Lock();
    
    m_pU2DRegsBase->u2dcsr[m_dwEndpointIndex] |= XLLP_U2DCCSR_PC    | XLLP_U2DCCSR_EFE| XLLP_U2DCCSR_FEF ;

    XllpU2DDisableInterrupt(m_pUsbDevice->GetXllpHandle(), 
                            (XLLP_U2D_INTERRUPTS_T)m_dwEndpointIndex, 
                            (XLLP_U2D_EP_INTERRUPT_TYPE_T)(U2D_SHORT_PACKET_COMPL_INT|U2D_PACKET_COMPL_INT|U2D_FIFO_ERROR_INT|U2D_DMA_STOP)
                            );

    Unlock();
    DEBUGMSG(ZONE_WARNING, (_T("ResetEndpoint- (%d) UDCCSR =0x%x UDCCRAX = 0x%x"),
        m_dwEndpointIndex,
        m_pU2DRegsBase->u2dcsr[m_dwEndpointIndex],
        m_pU2DRegsBase->u2dcr[m_dwEndpointIndex]));
    
    FUNCTION_LEAVE_MSG();
    return ERROR_SUCCESS;
}
DWORD USB20Endpoint::IsEndpointHalted(PBOOL pfHalted )
{
    Lock();
    
    if (m_fStalled)
        IST(0);
    if (pfHalted)
        *pfHalted = m_fStalled;
    
    Unlock();
    return ERROR_SUCCESS;
}
PSTransfer USB20Endpoint::CompleteTransfer(DWORD dwError)
{    
    if (m_pCurTransfer) 
    {

#ifdef DEBUG
        if(m_pCurTransfer->dwFlags & USB_IN_TRANSFER)
        {
            //DEBUGMSG(ZONE_DMAIN, (_T("Complete EP%d  %d \r\n"), m_dwEndpointIndex,m_Counter));
        }else
        {
            DEBUGMSG(ZONE_DMAOUT, (_T("Complete EP%d  %d \r\n"), m_dwEndpointIndex,m_Counter));
        }
#endif
        PSTransfer  pCurTransfer = m_pCurTransfer;
        m_pCurTransfer->dwUsbError= dwError;
        m_pCurTransfer = NULL;
        return pCurTransfer ;
    }
    return NULL;
}

USB20Endpoint::USB20Endpoint(USB20Device * const pUsbDevice, const DWORD dwPipeIndex,BOOL bDoubleBuffer) 
    :   m_pUsbDevice(pUsbDevice) ,   m_dwEndpointIndex((XLLP_U2D_EP_T)dwPipeIndex)   ,   m_fDoubleBuffer(bDoubleBuffer)
{
        m_vDesc=NULL;
        m_vDMAData=NULL;
        m_phyDesc=0;
        m_phyDMAData=0;
        
        static int inited=0;

        m_Counter=0;
        //  ------base              ------ DMA Descript 1 buffer
        //  ------base+16           ------ DMA Descript 2 buffer
        //  ------base+32           ------ DMA Data buffer 
        //  ------base+32+MAX_PKT_SIZE---- DMD Data buffer 2
        m_DmaAdapter.ObjectSize    = sizeof(DMA_ADAPTER_OBJECT);
        m_DmaAdapter.InterfaceType = Internal;
        m_DmaAdapter.BusNumber     = 0;

        m_vDesc=(P_XLLP_DMAC_DESCRIPTOR_T)HalAllocateCommonBuffer(&m_DmaAdapter, 
                                                                ( USB20_DMA_BUFFER_SIZE+(USB20_DESCRIPTORS_MAX+1)*sizeof(XLLP_DMAC_DESCRIPTOR_T)+4), 
                                                                 &m_PA, 
                                                                 FALSE);
                                                                                              
        m_vDMAData = (volatile XLLP_UINT8_T * )(m_vDesc+USB20_DESCRIPTORS_MAX+1);

        m_phyDesc=m_PA.LowPart;
        
        m_phyDMAData=m_phyDesc+(USB20_DESCRIPTORS_MAX+1)*sizeof(XLLP_DMAC_DESCRIPTOR_T);

        m_pCurTransfer = NULL;
        
        m_pU2DRegsBase=m_pUsbDevice->m_pRegsBase;

        //RETAILMSG(1,(_T("DMA Buffer VAdd = 0x%X, PAdd=0x%X\r\n"),m_vDesc,m_phyDesc));
}

USB20Endpoint::~USB20Endpoint()
{
    
    RETAILMSG(1,(_T("USB20Endpoint 0x%X Deleted \r\n"),this));

    XllpU2DDisableInterrupt(m_pUsbDevice->GetXllpHandle(), (XLLP_U2D_INTERRUPTS_T)m_dwEndpointIndex, U2D_INTR_ALL);
}
DWORD USB20Endpoint::IssueTransfer(PSTransfer pTransfer )
{
    DWORD dwReturn = ERROR_SUCCESS;
    SETFNAME();
    FUNCTION_ENTER_MSG();
    Lock();
    
    if (pTransfer!=NULL && m_pCurTransfer == NULL && (pTransfer->cbBuffer==0 || pTransfer->pvBuffer!=NULL) ) 
    { // If it is valid.        
        if (((pTransfer->dwFlags & USB_IN_TRANSFER)!= 0 )== ((m_epDesc.bEndpointAddress & 0x80)!=0)) 
        {

        __try{
            pTransfer ->pvPddData = (PVOID)m_dwEndpointIndex;
            m_pCurTransfer = pTransfer;
            m_pCurTransfer->cbTransferred = 0;
            m_pCurTransfer->pvPddData = (PVOID) m_dwEndpointIndex;
            m_fZeroPacket = (m_pCurTransfer->cbBuffer== 0 || m_pCurTransfer->pvBuffer== 0);
            }
    __except(EXCEPTION_EXECUTE_HANDLER) {
               //     DEBUGMSG(ZONE_ERROR, (_T("%s Exception!\r\n"), pszFname));
                dwReturn = ERROR_INVALID_DATA;
                   goto EXIT;
          }    
            //XllpU2DEnableInterrupt(   m_pUsbDevice->GetXllpHandle(), 
            //                      (XLLP_U2D_INTERRUPTS_T)m_dwEndpointIndex, 
            //                      (XLLP_U2D_EP_INTERRUPT_TYPE_T)(U2D_SHORT_PACKET_COMPL_INT|U2D_PACKET_COMPL_INT)
            //                     );
            
                     
            // Trigger First IST.
            m_Counter++;


            if(m_dwEndpointIndex != U2D_ENDPOINT_0 )
            {
                StartDMA();
            }
            else
            {
                IST((U2D_SHORT_PACKET_COMPL_INT|U2D_PACKET_COMPL_INT));
            }
 
        }
        else 
            dwReturn = ERROR_INVALID_DATA;
    }
    else 
        dwReturn = ERROR_NOT_READY;
    Unlock();
    FUNCTION_LEAVE_MSG();
    ASSERT(dwReturn == ERROR_SUCCESS);
EXIT:
    return dwReturn ;
}
DWORD USB20Endpoint::AbortTransfer(PSTransfer pTransfer )
{
    RETAILMSG(1,(_T("EP %d Cancel Transfer \r\n"), m_dwEndpointIndex));

    DWORD dwReturn = ERROR_SUCCESS;
    SETFNAME();
    FUNCTION_ENTER_MSG();
    Lock();
    PSTransfer pNotifyTransfer = NULL;
    if (pTransfer == m_pCurTransfer && m_pCurTransfer!=NULL) {
        ResetEndpoint();
        pNotifyTransfer = CompleteTransfer(UFN_CANCELED_ERROR);
    }
    else
        dwReturn = ERROR_INVALID_DATA;

    m_pU2DRegsBase->u2ddmacsr[m_dwEndpointIndex] &= ~XLLP_DMAC_DCSR_RUN;

    XllpU2DDisableInterrupt(m_pUsbDevice->GetXllpHandle(), 
                            (XLLP_U2D_INTERRUPTS_T)m_dwEndpointIndex, 
                            (XLLP_U2D_EP_INTERRUPT_TYPE_T)(U2D_DMA_STOP)
                            );
    
    Unlock();
    if (pNotifyTransfer)
        m_pUsbDevice->MddTransferComplete(pNotifyTransfer);
    FUNCTION_LEAVE_MSG();
    return dwReturn;
}

void USB20Endpoint::SendFakeFeature(BYTE bRequest,WORD wFeatureSelector)
{
    USB_DEVICE_REQUEST udr;
    PREFAST_DEBUGCHK(m_pUsbDevice!=NULL);
    udr.bmRequestType = USB_REQUEST_FOR_ENDPOINT;
    udr.bRequest = bRequest;
    udr.wValue = wFeatureSelector ;
    udr.wIndex = m_epDesc.bEndpointAddress ;
    udr.wLength =0;
    m_pUsbDevice->DeviceNotification( UFN_MSG_SETUP_PACKET,(DWORD) &udr);
}


BOOL USB20EndpointZero:: Init( PUSB_ENDPOINT_DESCRIPTOR pEndpointDesc,
            BYTE bConfigurationValue, BYTE bInterfaceNumber, BYTE bAlternateSetting)
{
    Lock();
    m_fBackedudr = FALSE;
    BOOL bReturn = FALSE;
    SETFNAME();
    FUNCTION_ENTER_MSG();

    DEBUGMSG(ZONE_FUNCTION, (_T("Enter.EP0 Init\r\n")));
   
    m_bConfigurationValue= bConfigurationValue;
    m_bInterfaceNumber = bInterfaceNumber;
    m_bAlternateSetting =bAlternateSetting;
    
    if ( pEndpointDesc && m_pUsbDevice!=NULL && m_dwEndpointIndex < XLLP_U2D_USB_MAX_EP_NUM) 
    {
        m_epDesc = *pEndpointDesc;
        //if ((m_epDesc.wMaxPacketSize & 0x3ff) >= U2D_EP0_MAX_PACKET_SIZE) 
        {
            m_epDesc.wMaxPacketSize = pEndpointDesc->wMaxPacketSize = U2D_EP0_MAX_PACKET_SIZE;
        
            bReturn = ReInit();
        }
    }

    Unlock();
    FUNCTION_LEAVE_MSG();
    return bReturn;
}

BOOL USB20EndpointZero::ReInit()
{
    m_bNeedAck = FALSE;
    m_bSetupDirIn = FALSE;
    DEBUGMSG(ZONE_FUNCTION, (_T("Enter.EP0 ReInit\r\n")));

    m_pU2DRegsBase->u2dcsr[U2D_ENDPOINT_0] = XLLP_U2DCCSR0_SA | XLLP_U2DCCSR0_SST | XLLP_U2DCCSR0_FTF | XLLP_U2DCCSR0_OPC;

//  m_pU2DRegsBase->u2dctrl = XLLP_U2DCR_EMCE;

    ClearDMAStatus();

    XllpU2DEnableInterrupt(m_pUsbDevice->GetXllpHandle(), 
                            (XLLP_U2D_INTERRUPTS_T)m_dwEndpointIndex, 
                            (XLLP_U2D_EP_INTERRUPT_TYPE_T)(U2D_SHORT_PACKET_COMPL_INT|U2D_PACKET_COMPL_INT)
                            );
    return TRUE;
}
DWORD USB20EndpointZero::ResetEndpoint()
{
    SETFNAME();
    FUNCTION_ENTER_MSG();
    Lock();

    m_bNeedAck = FALSE;

    m_pU2DRegsBase->u2dcsr[U2D_ENDPOINT_0] = XLLP_U2DCCSR0_SA | XLLP_U2DCCSR0_SST | XLLP_U2DCCSR0_FTF | XLLP_U2DCCSR0_OPC;

    ClearDMAStatus();
    XllpU2DEnableInterrupt(m_pUsbDevice->GetXllpHandle(), 
                            (XLLP_U2D_INTERRUPTS_T)m_dwEndpointIndex, 
                            (XLLP_U2D_EP_INTERRUPT_TYPE_T)(U2D_SHORT_PACKET_COMPL_INT|U2D_PACKET_COMPL_INT)
                            );
    ClearDMAStatus();
    XllpU2DDisableInterrupt(m_pUsbDevice->GetXllpHandle(), 
                            (XLLP_U2D_INTERRUPTS_T)m_dwEndpointIndex, 
                            (XLLP_U2D_EP_INTERRUPT_TYPE_T)U2D_DMA_ALL
                            );
    Unlock();
    FUNCTION_LEAVE_MSG();
    return ERROR_SUCCESS;
}
DWORD USB20EndpointZero::IssueTransfer(PSTransfer pTransfer )
{   
    Lock();
    SETFNAME();
    FUNCTION_ENTER_MSG();
    DWORD dwReturn = ERROR_SUCCESS;
    if (pTransfer!=NULL && pTransfer->pvBuffer!=NULL && m_pCurTransfer == NULL) 
    {   
    // If it is valid.                
        m_pCurTransfer = pTransfer;
        m_pCurTransfer->cbTransferred = 0;
        m_pCurTransfer->pvPddData = (PVOID) m_dwEndpointIndex;
        
        m_pCurTransfer->cbTransferred = 0;
        m_fZeroPacket = (m_pCurTransfer->cbBuffer== 0 || m_pCurTransfer->pvBuffer== 0);

        DEBUGMSG(ZONE_TRANSFER,(TEXT("Issue Transfer Zero size %d\r\n"),m_pCurTransfer->cbBuffer-m_pCurTransfer->cbTransferred));

        XllpU2DEnableInterrupt( m_pUsbDevice->GetXllpHandle(), 
                                    (XLLP_U2D_INTERRUPTS_T)m_dwEndpointIndex, 
                                    (XLLP_U2D_EP_INTERRUPT_TYPE_T)(U2D_SHORT_PACKET_COMPL_INT|U2D_PACKET_COMPL_INT)
                                   );
        
    }
    else 
        dwReturn = ERROR_INVALID_DATA;
    FUNCTION_LEAVE_MSG();
    Unlock();
    return dwReturn;
}
DWORD USB20EndpointZero::SendControlStatusHandshake()
{
    Lock();
    SETFNAME();
    DWORD dwReturn = ERROR_SUCCESS ;
    if (m_pCurTransfer == NULL && m_bNeedAck) 
    { // No Transfer.
        
        XllpU2DEnableInterrupt( m_pUsbDevice->GetXllpHandle(), 
                                    (XLLP_U2D_INTERRUPTS_T)m_dwEndpointIndex, 
                                    (XLLP_U2D_EP_INTERRUPT_TYPE_T)(U2D_SHORT_PACKET_COMPL_INT|U2D_PACKET_COMPL_INT)
                                   );
        if (!m_bSetupDirIn) 
        {
            DEBUGMSG(ZONE_TRANSFER, (_T("%s Ep0 m_bSetupDirIn =0 send zero package\r\n"),pszFname));
             
            m_pU2DRegsBase->u2dcsr[U2D_ENDPOINT_0] = XLLP_U2DCCSR0_OPC; //clear OPC
            m_pU2DRegsBase->u2dcsr[U2D_ENDPOINT_0] = XLLP_U2DCCSR0_IPR;
            
        }
        m_bNeedAck = FALSE;
        if (m_fBackedudr) 
        {
            m_bNeedAck = TRUE;
            m_bSetupDirIn = ((m_backup_udr.bmRequestType & USB_REQUEST_DEVICE_TO_HOST)!=0?TRUE:FALSE);
            m_fZeroPacket = FALSE;
            m_fBackedudr = FALSE;
            m_cur_udr = m_backup_udr ;
            m_pUsbDevice->DeviceNotification(UFN_MSG_SETUP_PACKET, (DWORD) &m_backup_udr);
            if (!m_fInIST) 
            {
                IST((U2D_SHORT_PACKET_COMPL_INT|U2D_PACKET_COMPL_INT));
            }
        }
        else if (m_bSetupDirIn && !m_fInIST )
            IST((U2D_SHORT_PACKET_COMPL_INT|U2D_PACKET_COMPL_INT));
        
        DEBUGMSG(ZONE_TRANSFER, (_T("%s Complete\r\n"),pszFname));
    }
    else
        DEBUGMSG(ZONE_TRANSFER, (_T("%s Skipped\r\n"),pszFname));
    Unlock();
    return ERROR_SUCCESS;
}


// COMPLETEWRITE()
//
//	The macro below will ensure a write to "ptr" completes.
//	"ptr" is usually a volatile pointer to a register.
//
//	A write register transaction can typically complete asynchronously.
//	This greatly improves the performance of a system. However, there
//	are some circumstances when software wants to gaurantee that a 
//	register update has completed before continuing exectuion. Setting
//	and clearing interrupt status bits are some examples of these 
//	situations.
//
//	Ensuring the write to "ptr" completes is a two step process:
//		step 1: read back the contents of "ptr"
//		step 2: make any use of the value read.
//
//	If step 2 is omitted, then the pipelining architecture of the core
//	may never stall at step 1 to wait for the write to complete. Step 2
//	allows the pipelining architecture of the core to determine that
//	there is a dependency on the completion of the read in step 1. So
//	it is the read in step 1, plus the dependency on read completion in
//	step 2, that cause the core to stall until these transactions complete.
//
//	This technique should be used whenever it is critical that a write 
//	to a register completes before code continues execution. 

#define COMPLETEWRITE(ptr)			\
{									\
	volatile unsigned long _tmp;	\
	_tmp=*((unsigned long*)(ptr));	\
	_tmp>1?1:0;						\
}


#define FLAG_COMPLETEWRITE	1

DWORD   USB20EndpointZero::IST(DWORD dwIRBit,DWORD DMA)
{
    Lock();
    BOOL bContinue = TRUE;
    m_fInIST = TRUE;
    SETFNAME();
    FUNCTION_ENTER_MSG();
	Sleep(1);
    if ((dwIRBit & U2D_FIFO_ERROR_INT)!=0) 
    { // FIFO Error. End
        DEBUGMSG(ZONE_TRANSFER, (_T("FIFO Error on Endpoint Zero UDCCSR=0x%x %d"),m_pU2DRegsBase->u2dcsr[U2D_ENDPOINT_0], dwIRBit));
        //XllpU2DDisableInterrupt(  m_pUsbDevice->GetXllpHandle(), 
        //                          (XLLP_U2D_INTERRUPTS_T)m_dwEndpointIndex, 
        //                          (XLLP_U2D_EP_INTERRUPT_TYPE_T)U2D_FIFO_ERROR_INT
        //                         );
    }
    while (bContinue && ((dwIRBit & (U2D_SHORT_PACKET_COMPL_INT|U2D_PACKET_COMPL_INT))!=0) ) 
    {
        bContinue = FALSE;
        m_fStalled = FALSE; // Endpoint Zero is auto clear stall condition.
        XLLP_UINT32_T csr = m_pU2DRegsBase->u2dcsr[U2D_ENDPOINT_0];
        
        DEBUGMSG(ZONE_TRANSFER, (_T("Endpoint Zero ReadControlStatusRegister()=0x%x\n"),csr));

        csr &= ~ (XLLP_U2DCCSR0_FST|XLLP_U2DCCSR0_IPA);

        if ( (csr&XLLP_U2DCCSR0_SA) && (csr&XLLP_U2DCCSR0_OPC)==0 ) 
        {
            m_pUsbDevice->IncBadSetupCounter();
            RETAILMSG(1, (_T("Endpoint Zero FAILED SETUP  udccsr=0x%x. Sent STALL FAKE\n"),csr));
	      	m_pU2DRegsBase->u2dcsr[U2D_ENDPOINT_0]= csr;
#ifdef FLAG_COMPLETEWRITE
			COMPLETEWRITE(&m_pU2DRegsBase->u2dcsr[U2D_ENDPOINT_0]);
#endif
			USB20EndpointZero::ResetEndpoint();
			m_pU2DRegsBase->u2dctrl |=XLLP_U2DCR_ADD;
	
			m_pU2DRegsBase->u2dctrl &= ~XLLP_U2DCR_UDE; //disable U2D
			m_pU2DRegsBase->u2dctrl &= ~XLLP_U2DCR_ADD;
			m_pU2DRegsBase->u2dctrl |= XLLP_U2DCR_UDE;

           // csr |= XLLP_U2DCCSR0_FST;
        }
        if (csr&XLLP_U2DCCSR0_OPC) 
        {
            if ( csr&XLLP_U2DCCSR0_SA ) 
            { // This is setup Packet.
                if (m_pCurTransfer) 
                { // Outstanding transfer.
                    //DebugBreak();
                    DEBUGMSG(ZONE_TRANSFER, (_T("Endpoint Zero Current Transfer Canceled\n")));
                    m_pU2DRegsBase->u2dcsr[U2D_ENDPOINT_0] = csr;
#ifdef FLAG_COMPLETEWRITE
					COMPLETEWRITE(&m_pU2DRegsBase->u2dcsr[U2D_ENDPOINT_0]);
#endif                    
                    PSTransfer pTransfer = CompleteTransfer( UFN_CANCELED_ERROR );
                    Unlock();
                    m_pUsbDevice->MddTransferComplete(pTransfer);
                    Lock();
                }

                if((csr&XLLP_U2DCCSR0_RNE) && m_pU2DRegsBase->u2dbcr[U2D_ENDPOINT_0] != sizeof (USB_DEVICE_REQUEST) )
                {
                    RETAILMSG(1, (_T("Setup package error  UDCCSR 0x%X Byte Counter: %d\r\n"), csr, m_pU2DRegsBase->u2dbcr[U2D_ENDPOINT_0] ));
                    m_pU2DRegsBase->u2dcsr[U2D_ENDPOINT_0] = XLLP_U2DCCSR0_OPC|XLLP_U2DCCSR0_SA;
#ifdef FLAG_COMPLETEWRITE
					COMPLETEWRITE(&m_pU2DRegsBase->u2dcsr[U2D_ENDPOINT_0]);
#endif
                    RETAILMSG(1, (_T("After Clear OPC UDCCSR 0x%X Byte Counter: %d\r\n"), csr, m_pU2DRegsBase->u2dbcr[U2D_ENDPOINT_0] ));
                    //ASSERT(ReadByteCountRegister() == sizeof (USB_DEVICE_REQUEST));
                }
                
                //if( m_pU2DRegsBase->u2dbcr[U2D_ENDPOINT_0] != sizeof (USB_DEVICE_REQUEST))
                //{
                //  RETAILMSG(TRUE, (_T("Assert EP0 FIFO Data count %d\r\n"),m_pU2DRegsBase->u2dbcr[U2D_ENDPOINT_0] ));
                //}
                
                USB_DEVICE_REQUEST udr;

                XllpU2DReadDwordFifo( m_pUsbDevice->GetXllpHandle(), U2D_ENDPOINT_0, (P_XLLP_UINT8_T) &udr, sizeof(USB_DEVICE_REQUEST) );
                
                DEBUGMSG(ZONE_TRANSFER, 
                    (_T("Endpoint Zero Setup bmRequestType = 0xx%x, bRequest=0x%x, wValue=0x%x,wIndex=0x%x,wLength=0x%x\n"),
                    udr.bmRequestType,udr.bRequest,udr.wValue,udr.wIndex,udr.wLength));
                
                if (m_bNeedAck) 
                { // Previous setup haven't ack yet. Disable Interrupt and wait for the Ack.
                    XllpU2DEnableInterrupt( m_pUsbDevice->GetXllpHandle(), 
                                    (XLLP_U2D_INTERRUPTS_T)m_dwEndpointIndex, 
                                    (XLLP_U2D_EP_INTERRUPT_TYPE_T)(U2D_SHORT_PACKET_COMPL_INT|U2D_PACKET_COMPL_INT)
                                   );
                    DEBUGMSG(ZONE_TRANSFER, (_T("Endpoint Zero Disable Interrupt")));
                    m_fBackedudr = TRUE;
                    m_backup_udr = udr;
                    m_pU2DRegsBase->u2dcsr[U2D_ENDPOINT_0] = csr;
#ifdef FLAG_COMPLETEWRITE
					COMPLETEWRITE(&m_pU2DRegsBase->u2dcsr[U2D_ENDPOINT_0]);
#endif
                    continue;
                }
                else 
                {
                    m_bNeedAck = TRUE;
                    m_bSetupDirIn = ((udr.bmRequestType & USB_REQUEST_DEVICE_TO_HOST)!=0?TRUE:FALSE);
                    bContinue = TRUE ;
                    m_fZeroPacket = FALSE;
                    m_cur_udr = udr ;
                    m_pU2DRegsBase->u2dcsr[U2D_ENDPOINT_0] = csr;
#ifdef FLAG_COMPLETEWRITE
					COMPLETEWRITE(&m_pU2DRegsBase->u2dcsr[U2D_ENDPOINT_0]);
#endif
                    m_pUsbDevice->DeviceNotification(UFN_MSG_SETUP_PACKET, (DWORD) &udr);
                }
                continue;
            }
            else if ( m_pU2DRegsBase->u2dbcr[U2D_ENDPOINT_0] == 0 ) 
            { // ACK from Host.
                DEBUGMSG(ZONE_TRANSFER, (_T("Endpoint Zero from Host ACK\r\n")));
                bContinue = TRUE; 
            }
            else if (m_pCurTransfer ) 
            {
                if((m_pCurTransfer->dwFlags & USB_IN_TRANSFER)==0) 
                {   // Out Data.
                    BOOL bComplete =  (m_pU2DRegsBase->u2dbcr[U2D_ENDPOINT_0]<m_epDesc.wMaxPacketSize);
                    
                    DWORD dwSize = (m_pCurTransfer->cbTransferred< m_pCurTransfer->cbBuffer? m_pCurTransfer->cbBuffer-m_pCurTransfer->cbTransferred: 0);
                    
                    if (dwSize!=0) 
                    {

                        dwSize=XllpU2DReadDwordFifo(    m_pUsbDevice->GetXllpHandle(), 
                                                        U2D_ENDPOINT_0, 
                                                        (PBYTE)m_pCurTransfer->pvBuffer + m_pCurTransfer->cbTransferred, 
                                                        dwSize );
                        
                        m_pCurTransfer->cbTransferred += dwSize;
                        DEBUGMSG(ZONE_TRANSFER, (_T("Endpoint Zero Get Data %d ACK\r\n"),dwSize));
                    }

                    bComplete = (bComplete || (m_pCurTransfer->cbTransferred>= m_pCurTransfer->cbBuffer));
                    // Check for the completeion.
                    if ( bComplete ) 
                    {
                        m_pU2DRegsBase->u2dcsr[U2D_ENDPOINT_0] =csr;
#ifdef FLAG_COMPLETEWRITE
						COMPLETEWRITE(&m_pU2DRegsBase->u2dcsr[U2D_ENDPOINT_0]);
#endif
                        PSTransfer pTransfer =CompleteTransfer(UFN_NO_ERROR);
                        bContinue = TRUE;
                        Unlock();
                        m_pUsbDevice->MddTransferComplete(pTransfer);
                        Lock();
                        continue;
                    }
                }
                else 
                {   // Error
                    csr|=XLLP_U2DCCSR0_FST;
                    DEBUGMSG(ZONE_TRANSFER, (_T("Endpoint Zero FSTr\n")));
                }
            }
            else 
            {   // Transfer Not queue yet. 
                XllpU2DDisableInterrupt(m_pUsbDevice->GetXllpHandle(), 
                                    (XLLP_U2D_INTERRUPTS_T)m_dwEndpointIndex, 
                                    U2D_INTR_ALL
                                   );
                // Do not clean OPC
                DEBUGMSG(ZONE_TRANSFER, (_T("Endpoint Zero Transfer Not queue yetr\n")));
                csr &=~XLLP_U2DCCSR0_OPC;
            }

        }
        
        if ( (m_pU2DRegsBase->u2dcsr[U2D_ENDPOINT_0]&XLLP_U2DCCSR0_IPR) == 0 ) 
        {
            
            // Because the Ep0 is half duplex. We assume the direction is correct.
            if (m_pCurTransfer && (m_pCurTransfer->dwFlags & USB_IN_TRANSFER)!=0 &&
                    m_pCurTransfer->cbTransferred <= m_pCurTransfer->cbBuffer) 
            {
                DWORD dwTotalData = m_pCurTransfer->cbBuffer - m_pCurTransfer->cbTransferred ;
                dwTotalData = min (dwTotalData,m_epDesc.wMaxPacketSize) ;
                // Spec 12.5.5
                DWORD dwReturn = XllpU2DWriteDwordFifo(m_pUsbDevice->GetXllpHandle(), 
                                                        U2D_ENDPOINT_0,
                                                        ((PBYTE)m_pCurTransfer->pvBuffer)+ m_pCurTransfer->cbTransferred, 
                                                        dwTotalData );
                        
                ASSERT(dwReturn == dwTotalData);
                
                m_pCurTransfer->cbTransferred += dwReturn;
                csr |= XLLP_U2DCCSR0_IPR ;
                if ( (dwTotalData &0x3)==3 )
                {
                    csr |= XLLP_U2DCCSR0_IPA;
                }
                
                DEBUGMSG(ZONE_TRANSFER, (_T("EP0 Send 0x%x\r\n"),dwTotalData));
                if (dwTotalData< m_epDesc.wMaxPacketSize) 
                {
                    m_fZeroPacket = FALSE;
                }
                else 
                    m_fZeroPacket = (m_cur_udr.wLength > m_pCurTransfer->cbTransferred);

                m_pU2DRegsBase->u2dcsr[U2D_ENDPOINT_0] = XLLP_U2DCCSR0_OPC; //make sure OPC have been cleared. 
#ifdef FLAG_COMPLETEWRITE
				COMPLETEWRITE(&m_pU2DRegsBase->u2dcsr[U2D_ENDPOINT_0]);
#endif                

			csr &=~XLLP_U2DCCSR0_OPC;   // make sure OPC will not be cleared twice.
                    
            }
        }
        else 
            csr &=~XLLP_U2DCCSR0_IPR ; // Do not set when there is packet.
            
        if (csr&XLLP_U2DCCSR0_SST) 
        { // Stall happens.
            m_pUsbDevice->IncEp0StallCounter() ;
            DEBUGMSG(ZONE_TRANSFER, (_T("Stall Sent on Zero endpoint =0x%x"),m_dwEndpointIndex));
        }

        // Clean the status.
        m_pU2DRegsBase->u2dcsr[U2D_ENDPOINT_0]= csr;
#ifdef FLAG_COMPLETEWRITE
		COMPLETEWRITE(&m_pU2DRegsBase->u2dcsr[U2D_ENDPOINT_0]);
#endif
        
        DEBUGMSG(ZONE_TRANSFER, (_T("CSR 0x%xcontinue:%d\r\n "),m_pU2DRegsBase->u2dcsr[U2D_ENDPOINT_0],bContinue));
        
        if (m_pCurTransfer &&m_pCurTransfer->cbTransferred >= m_pCurTransfer->cbBuffer && !m_fZeroPacket ) {// Complete anyway
            PSTransfer pTransfer = CompleteTransfer(UFN_NO_ERROR);
            Unlock();
            m_pUsbDevice->MddTransferComplete(pTransfer);
            Lock();            
        }
        
    }
    ClearDMAStatus();
    m_fInIST = FALSE;
    Unlock();
    FUNCTION_LEAVE_MSG();
    return ERROR_SUCCESS;
}



USB20EndpointIn::USB20EndpointIn(USB20Device * const pUsbDevice,DWORD dwEndpointIndex, BOOL bDoubleBuffer)
        : USB20Endpoint(pUsbDevice, dwEndpointIndex ,bDoubleBuffer ) 
{
    DEBUGMSG(ZONE_TRANSFER, (_T("EndPoint IN Create: %d \r\n"),dwEndpointIndex));
    m_pU2DRegsBase->u2dcsr[m_dwEndpointIndex] |= XLLP_U2DCCSR_DME;
}



void   USB20EndpointIn::StartDMA()
{
    int size;
    Lock();
    DWORD csr=0;
    
    if(!m_fZeroPacket)
    {
        size=(m_pCurTransfer->cbBuffer-m_pCurTransfer->cbTransferred);
        if(size>(USB20_DESCRIPTORS_MAX*(m_epDesc.wMaxPacketSize & 0x3ff)))
            size =(USB20_DESCRIPTORS_MAX*(m_epDesc.wMaxPacketSize & 0x3ff));

        if(size>USB20_DMA_BUFFER_SIZE)
            size = USB20_DMA_BUFFER_SIZE;
            
    }else
    {
        size=0;
    }   

    m_pU2DRegsBase->u2dcsr[m_dwEndpointIndex] = XLLP_U2DCCSR_DME;
    
    __try{
        memcpy((void*)m_vDMAData,(PBYTE)m_pCurTransfer->pvBuffer + m_pCurTransfer->cbTransferred, size);
    } //try
    __except(EXCEPTION_EXECUTE_HANDLER) {
//        DEBUGMSG(ZONE_ERROR, (_T("%s Exception!\r\n"), pszFname));
        goto ERROR_HANDLE;
    }  


    if(!( m_pUsbDevice->m_pRegsBase->u2ddmacsr[m_dwEndpointIndex] & XLLP_DMAC_DCSR_STOP_INTR ) )
    {
        RETAILMSG(TRUE, (_T("DMA NOT STOP\r\n")));
    }
        
        
   // DEBUGMSG(ZONE_DMAIN, (_T("DMASR =0x%X\r\n ")
    //  ,m_pU2DRegsBase->u2ddmacsr[m_dwEndpointIndex]));

    XLLP_U2D_TRANSFER_T Transfer;
    Transfer.direct = XLLP_USB_IN;
    Transfer.EnableEndIrq = XLLP_FALSE;
    Transfer.isZeroPackage = (XLLP_BOOL_T)m_fZeroPacket;
    Transfer.len = size;
    Transfer.physicalAddress = m_phyDMAData; 
    Transfer.udcEndpointNum = m_dwEndpointIndex;


    XllpU2DStartTransfer(m_pUsbDevice->GetXllpHandle(),  &Transfer);
    
#ifdef DEBUG    
    DumpDescript();
#endif  

    m_pU2DRegsBase->u2ddmacsr[m_dwEndpointIndex]|=U2D_DMA_STOP;
    m_pU2DRegsBase->u2ddmacsr[m_dwEndpointIndex]|=XLLP_DMAC_DCSR_RUN;

ERROR_HANDLE:
    Unlock();
 }
    


DWORD   USB20EndpointIn::IST(DWORD dwIRBit,DWORD DMA)
{
    Lock();
    BOOL bContinue = TRUE;
    SETFNAME();
    FUNCTION_ENTER_MSG();
    if ((dwIRBit & U2D_FIFO_ERROR_INT)!=0) 
    { // FIFO Error. End
      
        DEBUGMSG(ZONE_WARNING, (_T("FIFO Error on Endpoint IN(%d) UDCCSR=0x%x"),m_dwEndpointIndex,m_pU2DRegsBase->u2dcsr[m_dwEndpointIndex]));
    }
    while (bContinue) 
    { // Loop until all the event clear.
        bContinue = FALSE;
        XLLP_UINT32_T csr= m_pU2DRegsBase->u2dcsr[m_dwEndpointIndex];
        XLLP_UINT32_T DmaStatus=m_pU2DRegsBase->u2ddmacsr[m_dwEndpointIndex];

        csr &=~XLLP_U2DCCSR_SP;
        
        //u2d DMA handle
        if( (DmaStatus & XLLP_DMAC_DCSR_STOP_INTR) && (DmaStatus & XLLP_DMAC_DCSR_STOP_IRQ_EN))
        //if( DmaStatus & XLLP_DMAC_DCSR_END_INTR)
        {
            XLLP_UINT32_T size;
            ClearDMAStatus();

            if(m_pCurTransfer==NULL)
            {
                RETAILMSG(1,(_T("pCurTransfer In is NULL\r\n")));
                continue;
            }
                    
            XllpU2DGetTransferStatus(m_pUsbDevice->GetXllpHandle(), m_dwEndpointIndex, &size);


            
            csr &=~XLLP_U2DCCSR_PC; //DMA auto clear PC;    
            //m_pU2DRegsBase->u2dcsr[m_dwEndpointIndex] = XLLP_U2DCCSR_PC|XLLP_U2DCCSR_EFE; 
            
            m_pCurTransfer->cbTransferred +=size;
    
            if ( m_pCurTransfer &&  m_pCurTransfer->cbTransferred >= m_pCurTransfer->cbBuffer) 
            {
                

                ASSERT( m_pCurTransfer->cbTransferred == m_pCurTransfer->cbBuffer );
                
                   
                
                PSTransfer pTransfer = CompleteTransfer(UFN_NO_ERROR);
                m_pUsbDevice->MddTransferComplete(pTransfer);
                break;
                
            }else if ( m_pCurTransfer->cbTransferred < m_pCurTransfer->cbBuffer )
            {   
                StartDMA();
                break;
            }
            continue;
        }

        //u2d control process
        
        
        if ( m_fStalled && ( (csr&XLLP_U2DCCSR_PC)  || (csr&XLLP_U2DCCSR_EFE) ) ) 
        {
            // Stall has been clear silently. So we generate Faking Clear Feature for Endpoint Zero

            DEBUGMSG(ZONE_TRANSFER, (_T("Stall IST IN\r\n")));
            
            m_fStalled = FALSE;
            csr &=~ (XLLP_U2DCCSR_PC |XLLP_U2DCCSR_EFE|XLLP_U2DCCSR_FEF);
            m_pU2DRegsBase->u2dcsr[m_dwEndpointIndex] = csr;
            
            bContinue = TRUE;
            SendFakeFeature(USB_REQUEST_CLEAR_FEATURE,USB_FEATURE_ENDPOINT_STALL);
            continue;
        }

         
        if ( csr&XLLP_U2DCCSR_PC ) 
        { // Packet Complete.
            if (csr&XLLP_U2DCCSR_DPE ) 
            { // Data Packet Error
                m_pU2DRegsBase->u2dcsr[m_dwEndpointIndex] = csr;
               
                PSTransfer pTransfer = CompleteTransfer(UFN_NOT_COMPLETE_ERROR);
                Unlock();
                m_pUsbDevice->MddTransferComplete(pTransfer);
                Lock();
                continue;
            }
        }
        
        csr &=~XLLP_U2DCCSR_SP;
    
        if (csr&XLLP_U2DCCSR_SST) 
        {
            DEBUGMSG(ZONE_WARNING, (_T("Stall send on In Endpoint = 0x%x"),m_dwEndpointIndex));
            // We have to assume we clean stall here because this no more interrupt.
            csr &=~XLLP_U2DCCSR_FST;
            m_fStalled = FALSE;
            bContinue = TRUE;

            m_pU2DRegsBase->u2dcsr[m_dwEndpointIndex] = csr;

            SendFakeFeature(USB_REQUEST_CLEAR_FEATURE,USB_FEATURE_ENDPOINT_STALL);
            continue;
        }

        
    }
    Unlock();
    FUNCTION_LEAVE_MSG();
    return ERROR_SUCCESS;
    
}


USB20EndpointOut::USB20EndpointOut(USB20Device * const pUsbDevice,DWORD dwEndpointIndex, BOOL bDoubleBuffer)
        : USB20Endpoint(pUsbDevice, dwEndpointIndex ,bDoubleBuffer) 
{

    DEBUGMSG(ZONE_TRANSFER, (_T("EndPoint Out Create: %d\r\n"),dwEndpointIndex));
   
}


DWORD USB20EndpointOut:: UpdateFromDMABuffer()
{
    Lock();
    DWORD size;
    if ( m_pCurTransfer ) 
    {
        size=(m_pCurTransfer->cbBuffer-m_pCurTransfer->cbTransferred);

        // DMA IST and UDC SP IST issue at the same time. This case happen at only the last package. 
        // In this case, UpdateFromDMABuffer will call twice. 
        if(size<=0)
        {
            Unlock();
            return 0;
        }

        XllpU2DGetTransferStatus(m_pUsbDevice->GetXllpHandle(), 
                                m_dwEndpointIndex, 
                                &size);
        ASSERT(((int)size)>=0);
        
    
        if( m_pCurTransfer->dwBufferPhysicalAddress == 0 )
        {
              __try{
                   memcpy((PBYTE)(m_pCurTransfer->pvBuffer) + m_pCurTransfer->cbTransferred,(const void *)m_vDMAData,size);
            }//try
        __except(EXCEPTION_EXECUTE_HANDLER) {
        //    DEBUGMSG(ZONE_ERROR, (_T("%s Exception!\r\n"), pszFname));
            goto ERROR_HANDLE;
            }
        }   
#ifdef DEBUG
        //DumpData((unsigned char *)(m_pCurTransfer->pvBuffer) + m_pCurTransfer->cbTransferred, size);
#endif      
        m_pCurTransfer->cbTransferred+=size;
           
        m_LastTransfer=size;
    }

    Unlock();
    return size;
ERROR_HANDLE:    
    Unlock();
    
    return 0;
}

void   USB20EndpointOut::StartDMA()
{
    Lock();
    int size;

    //RETAILMSG(1, (_T("Start DMA Out\r\n")));
    size = (m_pCurTransfer->cbBuffer - m_pCurTransfer->cbTransferred);

    if(size>USB20_DMA_BUFFER_SIZE)
        size = USB20_DMA_BUFFER_SIZE;

    m_pU2DRegsBase->u2dcsr[m_dwEndpointIndex] = XLLP_U2DCCSR_DME;
    
    XLLP_U2D_TRANSFER_T Transfer;
    Transfer.direct = XLLP_USB_OUT;
    Transfer.EnableEndIrq = XLLP_FALSE;

    
    if( m_pCurTransfer->dwBufferPhysicalAddress == 0 )
    {
        Transfer.physicalAddress = m_phyDMAData; 
        
    }else
    {
        Transfer.physicalAddress = m_pCurTransfer->dwBufferPhysicalAddress+ m_pCurTransfer->cbTransferred;
        size=m_pCurTransfer->cbBuffer - m_pCurTransfer->cbTransferred;
    }   

    Transfer.len = size;
    
    Transfer.udcEndpointNum = m_dwEndpointIndex;
        
    XllpU2DStartTransfer(m_pUsbDevice->GetXllpHandle(),  &Transfer);

    
    //XllpU2DEnableInterrupt(m_pUsbDevice->GetXllpHandle(), 
    //                  (XLLP_U2D_INTERRUPTS_T)m_dwEndpointIndex, 
    //                  (XLLP_U2D_EP_INTERRUPT_TYPE_T)(U2D_DMA_STOP|U2D_DMA_EORSTOP)
    //                    );

    m_pU2DRegsBase->u2ddmacsr[m_dwEndpointIndex] |=XLLP_DMAC_DCSR_RUN|U2D_DMA_STOP|U2D_DMA_EORSTOP;
    
    //m_pU2DRegsBase->u2ddmacsr[m_dwEndpointIndex] |=XLLP_DMAC_DCSR_RUN;
    
    Unlock();
}

DWORD   USB20EndpointOut::IST(DWORD dwIRBit,DWORD DMA)
{
    Lock();
    BOOL bContinue = TRUE;
    //DWORD dataendoff;
    SETFNAME();
    FUNCTION_ENTER_MSG();

    if ((dwIRBit & U2D_FIFO_ERROR_INT)!=0) 
    { // FIFO Error. End
        DEBUGMSG(ZONE_WARNING, (_T("FIFO Error on Endpoint Out(%d) UDCCSR=0x%x"),m_dwEndpointIndex,m_pU2DRegsBase->u2dcsr[m_dwEndpointIndex]));
    }
 
    while (bContinue)   
    {
        bContinue = FALSE;

        XLLP_UINT32_T udccsr = m_pU2DRegsBase->u2dcsr[m_dwEndpointIndex];
        XLLP_UINT32_T DmaStatus = m_pU2DRegsBase->u2ddmacsr[m_dwEndpointIndex];
        
        if (m_fStalled && ( (udccsr&XLLP_U2DCCSR_PC) ||(udccsr&XLLP_U2DCCSR_EFE) ) ) 
        {
            // Stall has been clear silently. So we generate Faking Clear Feature for Endpoint Zero
            m_fStalled = FALSE;
            udccsr &=~(XLLP_U2DCCSR_PC | XLLP_U2DCCSR_EFE | XLLP_U2DCCSR_FEF );
            
            m_pU2DRegsBase->u2dcsr[m_dwEndpointIndex] = udccsr;
            bContinue = TRUE;
            SendFakeFeature(USB_REQUEST_CLEAR_FEATURE,USB_FEATURE_ENDPOINT_STALL);
            continue;
        }   

        //DMA Interrupt
        if ( (DmaStatus & XLLP_DMAC_DCSR_STOP_INTR ) && DMA )
        {
            DEBUGMSG(ZONE_DMAOUT, (_T("DMA OUT STOP DMA Status: 0x%x, CSR: 0x%x\r\n"),DmaStatus,udccsr));
            ClearDMAStatus();
            
            if(m_pCurTransfer!=NULL)
            {
                //XllpU2DDisableInterrupt(m_pUsbDevice->GetXllpHandle(), (XLLP_U2D_INTERRUPTS_T)m_dwEndpointIndex, U2D_DMA_ALL);
                
                UpdateFromDMABuffer();
        
                //if(m_pCurTransfer->cbTransferred>=m_pCurTransfer->cbBuffer)
                if( ( (m_pU2DRegsBase->ddg[m_dwEndpointIndex].dcmd&XLLP_U2DDAM_CMD_LEN_MASK) != 0 ) ||
                    (m_pCurTransfer->cbTransferred>=m_pCurTransfer->cbBuffer))
                    
                {
                    m_pU2DRegsBase->u2dcsr[m_dwEndpointIndex] = XLLP_U2DCCSR_PC|XLLP_U2DCCSR_EFE;
                    PSTransfer pTransfer = CompleteTransfer(UFN_NO_ERROR);
                    Unlock();
                    m_pUsbDevice->MddTransferComplete(pTransfer);
                    Lock();
                    break;
                }
                else
                { /// There are more data that need be received. 
                    StartDMA();
                    break;
                }
            }
        }

    
        if(  (udccsr&XLLP_U2DCCSR_SP) && (dwIRBit&U2D_SHORT_PACKET_COMPL_INT))
        {
            break;
        }

        if (udccsr&XLLP_U2DCCSR_SST) 
        {
            DEBUGMSG(ZONE_WARNING, (_T("Stall Sent on Out endpoint =0x%x"),m_dwEndpointIndex));
            m_fStalled = TRUE;
            bContinue = TRUE;
        }

   }
   

   Unlock();
   FUNCTION_LEAVE_MSG();
   return ERROR_SUCCESS;
}


USB20Device::USB20Device(LPCTSTR lpActivePath )
:   CRegistryEdit(lpActivePath)
,   CMiniThread (0, TRUE)   
{
    m_hISTEvent = NULL;
    m_pDCCLKReg = NULL;
    m_fDoubleBuffer = TRUE;
    m_pvMddContext = NULL;
    m_dwCurConfigure = MAXDWORD;
    m_dwCurInterface = MAXDWORD;
    m_pfnNotify = NULL;
    m_CurPowerState = PwrDeviceUnspecified ;
    m_hParent = CreateBusAccessHandle(lpActivePath);    
    m_dwSysIntr = SYSINTR_UNDEFINED;

    m_pRegsBase=NULL;  
    m_pMfpRegBase=NULL;
    m_pGPIORegs=NULL;   
    m_pMfpRMDb=NULL;        
    m_MfpRMDHandle=NULL;
    m_busSpeed=BS_UNKNOWN_SPEED;   
    memset(GetXllpHandle(), 0, sizeof(m_XllpU2DHandle));
}

USB20Device::~USB20Device()
{
    if (m_dwSysIntr != SYSINTR_UNDEFINED ) 
    {
        KernelIoControl(IOCTL_HAL_RELEASE_SYSINTR, &m_dwSysIntr, sizeof(DWORD),NULL,0,NULL);
        m_dwSysIntr = SYSINTR_UNDEFINED;
    }
            
    if (m_hISTEvent) 
    {
        m_bTerminated=TRUE;
        ThreadStart();
        SetEvent(m_hISTEvent);
        ThreadTerminated(1000);
        InterruptDisable( m_dwSysIntr );         
        CloseHandle(m_hISTEvent);
    }
    for (DWORD dwIndex =0 ; dwIndex <XLLP_U2D_USB_MAX_EP_NUM; dwIndex ++) 
    {
        RemoveObjectBy( dwIndex );
    }

    if (m_pRegsBase!=NULL) 
    {
        m_pRegsBase->u2dicr = 0;
        m_pRegsBase ->u2dctrl = 0 ;
        MmUnmapIoSpace((PVOID)m_pRegsBase,0UL);
        m_pRegsBase=NULL;
    }

    if (m_pMfpRegBase!=NULL) 
    {
        
        MmUnmapIoSpace((PVOID)m_pMfpRegBase,0UL);
        m_pMfpRegBase=NULL;
    }
    
    if (m_pGPIORegs!=NULL) 
    {
        
        MmUnmapIoSpace((PVOID)m_pGPIORegs,0UL);
        m_pGPIORegs=NULL;
    }

    if (m_pDCCLKReg) 
    {
        //m_pDCCLKReg->cken &= ~XLLP_CLKEN_USBCLIENT ;
        XllpClockEnable((P_XLLP_CLKMGR_T)m_pDCCLKReg, XLLP_CLK_USB2, XLLP_FALSE);
        MmUnmapIoSpace((PVOID)m_pDCCLKReg,0);
        m_pDCCLKReg=NULL;
    }

    if (m_pMfpRMDb)
    {
        CloseHandle(m_MfpRMDHandle);
    }

    m_MfpRMDHandle=NULL;
    
    //if(m_pBPMUReg)
    //{
    //   MmUnmapIoSpace((PVOID)m_pBPMUReg,0);
    //  m_pBPMUReg=NULL;
    //}

    if (m_hParent)
        CloseBusAccessHandle(m_hParent);
}
DWORD USB20Device::Init(
    PVOID                       pvMddContext,
    PUFN_MDD_INTERFACE_INFO     pMddInterfaceInfo,
    PUFN_PDD_INTERFACE_INFO     pPddInterfaceInfo
    )
{
    m_pvMddContext = pvMddContext;
    m_pfnNotify = pMddInterfaceInfo->pfnNotify;
    pPddInterfaceInfo->pvPddContext = this;

/*
    BSP_ARGS args;
    DWORD size;
    
    if(KernelIoControl(IOCTL_GET_BSP_ARGS,NULL,0,&args,sizeof(args),&size))
    {
        if(args.DefaultUSBClient != BSP_ARGS_USB_CLIENT_2_0)
        {
            RETAILMSG(1, (_T("EBOOT Config Don't use USB 2.0 as client\r\n")));
            return ERROR_INVALID_DATA;
        }
    }
*/
    
    if ( !IsKeyOpened())
        return ERROR_INVALID_DATA; 

    //---------- Configurate DMA
    m_PDDInfo.BusNumber=0;
    m_PDDInfo.dwAlignment=0;
    m_PDDInfo.InterfaceType=Internal;
    
    DDKWINDOWINFO dwi;
    DWORD dwRet = GetWindowInfo(&dwi);
    if(dwRet != ERROR_SUCCESS) 
    {
        DEBUGMSG(ZONE_INIT, (_T("USB20Device:: DDKReg_GetWindowInfo() failed %d\r\n"), dwRet));
        return dwRet;
        
    } else if(dwi.dwNumMemWindows != 1) 
    {
        return ERROR_INVALID_DATA;
    }
    else if (dwi.memWindows[0].dwLen < sizeof(XLLP_U2D_REGISTERS_T)) 
    {
        DEBUGMSG(ZONE_INIT, (_T("memLen of 0x%x is less than required 0x%x\r\n"),
            dwi.memWindows[0].dwLen, sizeof(XLLP_U2D_REGISTERS_T)));
        return ERROR_INVALID_DATA;
    }
    
    m_fIsCableAttached = FALSE;
    m_fResumeOccurred = FALSE;
    m_fForceResume = FALSE;

    
    if (m_pDCCLKReg == NULL ) 
    {
        PHYSICAL_ADDRESS ioPhysicalBase = {MONAHANS_BASE_REG_PA_CLKMGR, 0 };
        m_pDCCLKReg = (P_XLLP_CLKMGR_T)MmMapIoSpace(ioPhysicalBase, sizeof(XLLP_CLKMGR_T),FALSE);
        if (m_pDCCLKReg != NULL)
        //    m_pDCCLKReg->cken |= XLLP_CLKEN_USBCLIENT ;
            XllpClockEnable(m_pDCCLKReg, XLLP_CLK_USB2, XLLP_TRUE);
        else
            return ERROR_INVALID_DATA;            
    }
    
    // Map Windows.
    // Translate to System Address.
    if ( m_pRegsBase == NULL ) {
        PHYSICAL_ADDRESS    ioPhysicalBase = { dwi.memWindows[0].dwBase, 0};
        m_pRegsBase = (P_XLLP_U2D_REGISTERS_T) MmMapIoSpace(ioPhysicalBase, dwi.memWindows[0].dwLen,FALSE);
        if (m_pRegsBase == NULL )
            return ERROR_INVALID_DATA;
    }

    if (m_pGPIORegs == NULL )
    {
        PHYSICAL_ADDRESS    ioPhysicalBase = { MONAHANS_BASE_REG_PA_GPIO, 0};
        m_pGPIORegs = (P_XLLP_GPIO_T) MmMapIoSpace(ioPhysicalBase, sizeof(XLLP_GPIO_T),FALSE);
        if (m_pGPIORegs== NULL )
            return ERROR_INVALID_DATA;
   
    }   

    if (m_pMfpRegBase  == NULL )
    {
        PHYSICAL_ADDRESS    ioPhysicalBase = { MONAHANS_BASE_REG_PA_MFP, 0};
        m_pMfpRegBase = (P_XLLP_VUINT32_T) MmMapIoSpace(ioPhysicalBase, 0x1000,FALSE);
        if (m_pMfpRegBase== NULL )
            return ERROR_INVALID_DATA;
    }
    
    if (!InitMFPRM())
        return ERROR_INVALID_DATA;
        
    
    XllpU2DInitHandle(&m_XllpU2DHandle, m_pRegsBase, m_pMfpRegBase, m_pGPIORegs, m_pMfpRMDb);
        

    DEBUGMSG(ZONE_INIT, (_T("CLKReg is 0x%x\r\n"),m_pDCCLKReg));
    RETAILMSG(1, (_T("UDCReg is 0x%x\r\n"),m_pRegsBase));
    //DEBUGMSG(ZONE_INIT, (_T("PSSR   is 0x%x\r\n"),m_pPwrReg));

    // get ISR configuration information
    DWORD Irq= XLLP_INTC_S_USB2 ;
    if (!KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &Irq, sizeof(DWORD), &(m_dwSysIntr), sizeof(DWORD), NULL))
    {
        // invalid SDIO SYSINTR value!
        DEBUGMSG(ZONE_ERROR, (TEXT("Error obtaining PowerIC SYSINTR value!\n")));
        m_dwSysIntr = SYSINTR_UNDEFINED;
        return ERROR_INVALID_DATA;
    }
        
    
    m_hISTEvent= CreateEvent(0,FALSE,FALSE,NULL);
    if (m_hISTEvent!=NULL)
        InterruptInitialize(m_dwSysIntr,m_hISTEvent,0,0);
    else
       return ERROR_INVALID_DATA;
        
    // Optional Registry.
    DWORD dwDataSize = sizeof(DWORD);
    DWORD dwDoubleBuffer = 1;
    
    // Read the IST priority
    dwDataSize = sizeof(m_dwPriority);

    if (!GetRegValue(USB20FUNCTION_PRIORITY_VALNAME,(LPBYTE) &m_dwPriority, dwDataSize)) 
    {
        m_dwPriority = USB20FUNCTION_DEFAULT_PRIORITY;
    }

    CeSetPriority(m_dwPriority);

    if (HardwareInit()) 
    {
        ThreadStart();
        return ERROR_SUCCESS;
    } 
    else
        return ERROR_INVALID_DATA;
    
}
BOOL USB20Device::HardwareInit()
{
    BOOL bReturn = TRUE;
    SETFNAME();
    FUNCTION_ENTER_MSG();
    Lock();
    // Disable Hardware
    XLLP_UINT32_T udccr;


    udccr = GetXllpHandle() -> pRegsBase ->u2dctrl;
    udccr |= XLLP_U2DCR_EMCE;	
    udccr &= ~ (XLLP_U2DCR_UDE);
    GetXllpHandle() -> pRegsBase ->u2dctrl = udccr;
    //GetXllpHandle() -> pRegsBase ->u2dicr = 0;

    
    // Ack all outstanding interrupt.
    GetXllpHandle() -> pRegsBase ->u2disr = 0xFFFFFFFF;

    GetXllpHandle() -> pRegsBase ->u2disr2 = 0xFFFFFFFF;

    
    Unlock();
    FUNCTION_LEAVE_MSG();
    return bReturn;
}
BOOL   USB20Device::ReInit() // For Cable Detach & Attach , We have to re-init the Device Controller.
{

    Lock();
    HardwareInit();
    Start();
    
    for (DWORD dwIndex=0; dwIndex<XLLP_U2D_USB_MAX_EP_NUM; dwIndex++)
    {
        USB20Endpoint *pEndpoint = ObjectIndex(dwIndex);
        if (pEndpoint!=NULL)  
        {
            pEndpoint->ReInit();
            pEndpoint->DeRef();
        }
    }   
        
    //PVOID pvMddContext = m_pvMddContext;
    //m_pvMddContext = NULL;
    
    
    for (dwIndex=0; dwIndex<XLLP_U2D_USB_MAX_EP_NUM; dwIndex++)
        if ( RawObjectIndex(dwIndex)!=NULL) 
        {
            if(dwIndex==0)
            {
                XllpU2DEnableInterrupt( GetXllpHandle(), 
                                    (XLLP_U2D_INTERRUPTS_T)dwIndex, 
                                    (XLLP_U2D_EP_INTERRUPT_TYPE_T)(U2D_SHORT_PACKET_COMPL_INT|U2D_PACKET_COMPL_INT)
                                   );
            }else
            {
                XllpU2DDisableInterrupt(    GetXllpHandle(), 
                                    (XLLP_U2D_INTERRUPTS_T)dwIndex, 
                                    (XLLP_U2D_EP_INTERRUPT_TYPE_T)U2D_INTR_ALL
                                   );
            
            }
                
        }
    
    Unlock();
    return FALSE;
}
BOOL USB20Device::DeleteAllEndpoint()
{
    for (DWORD dwIndex=0; dwIndex<XLLP_U2D_USB_MAX_EP_NUM; dwIndex++)
        RemoveObjectBy( dwIndex );
    return TRUE;
}

// Interface Function.
DWORD USB20Device::IsEndpointSupportable (DWORD dwEndpoint,UFN_BUS_SPEED Speed,PUSB_ENDPOINT_DESCRIPTOR pEndpointDesc,
            BYTE bConfigurationValue, BYTE bInterfaceNumber, BYTE bAlternateSetting )
{
    DWORD dwError = ERROR_INVALID_PARAMETER;
    SETFNAME();
    DEBUGMSG(ZONE_FUNCTION, (_T("%s Enter. dwEndpoint:0x%x,Speed:0x%x --\r\n"), pszFname,dwEndpoint,Speed));
    Lock();
    if ( (Speed == BS_FULL_SPEED || Speed == BS_HIGH_SPEED)  
            &&  pEndpointDesc  &&
            dwEndpoint < XLLP_U2D_USB_MAX_EP_NUM  ) 
    {

        if(RawObjectIndex(dwEndpoint))
        {// Endpoint have created
            dwError = ERROR_SUCCESS;
            
        }else
        {//Endpoint have not created
            
           USB20Endpoint *pEndpoint = NULL;
           if (dwEndpoint == 0 ) // Endpoint Zero.
                pEndpoint = new USB20EndpointZero(this,m_fDoubleBuffer);
           else 
           {   
               DWORD ret=0;
               DWORD value=0;

               if ( (pEndpointDesc->bEndpointAddress & 0x80)!=0) 
               {
                   pEndpoint = new USB20EndpointIn(this,dwEndpoint,m_fDoubleBuffer);
               }
               else 
               {
                    pEndpoint = new USB20EndpointOut(this,dwEndpoint,m_fDoubleBuffer);
               }
           }
           if (pEndpoint &&  pEndpoint->Init(pEndpointDesc,bConfigurationValue,bInterfaceNumber,bAlternateSetting)) 
           {
               dwError = ERROR_SUCCESS;
               InsertObject(dwEndpoint, pEndpoint) ;
           }
           else 
            {
               if (pEndpoint) 
                {
                   delete pEndpoint;
               }
           }
        }
    }
    Unlock();
    ASSERT(dwError == ERROR_SUCCESS);
    DEBUGMSG(ZONE_FUNCTION, (_T("%s return errorcode = %d --\r\n"), pszFname,dwError));
    return dwError;
}
DWORD USB20Device::InitEndpoint(DWORD dwEndpoint,UFN_BUS_SPEED Speed,PUSB_ENDPOINT_DESCRIPTOR pEndpointDesc,
            BYTE bConfigurationValue, BYTE bInterfaceNumber, BYTE bAlternateSetting )
{
    DWORD dwError = ERROR_INVALID_PARAMETER;
    SETFNAME();
    FUNCTION_ENTER_MSG();
    USB20Endpoint *pEndpoint = ObjectIndex(dwEndpoint);
    if (pEndpoint) {
        dwError = pEndpoint->InitEndpoint(Speed, pEndpointDesc);
        pEndpoint->DeRef();
    }
    FUNCTION_LEAVE_MSG();
    return dwError;
};

DWORD USB20Device::DeinitEndpoint(DWORD dwEndpoint )
{
    DWORD dwError = ERROR_INVALID_PARAMETER;
    SETFNAME();
    FUNCTION_ENTER_MSG();
    USB20Endpoint *pEndpoint = ObjectIndex(dwEndpoint);
    if (pEndpoint) {
        dwError = pEndpoint->DeinitEndpoint();
        pEndpoint->DeRef();
    }
    FUNCTION_LEAVE_MSG();
    return dwError;
    
}
DWORD USB20Device::StallEndpoint(DWORD dwEndpoint )
{
    DWORD dwError = ERROR_INVALID_PARAMETER;
    SETFNAME();
    FUNCTION_ENTER_MSG();
    RETAILMSG(1, (_T("Statll %d\r\n"), dwEndpoint));
    USB20Endpoint *pEndpoint = ObjectIndex(dwEndpoint);
    if (pEndpoint) {
        dwError = pEndpoint->StallEndpoint();
        pEndpoint->DeRef();
    }
    FUNCTION_LEAVE_MSG();
    return dwError;
}
DWORD USB20Device::ClearEndpointStall( DWORD dwEndpoint )
{
    DWORD dwError = ERROR_INVALID_PARAMETER;
    SETFNAME();
    FUNCTION_ENTER_MSG();
    USB20Endpoint *pEndpoint = ObjectIndex(dwEndpoint);
    if (pEndpoint) {
        dwError = pEndpoint->ClearEndpointStall();
        pEndpoint->DeRef();
    }
    FUNCTION_LEAVE_MSG();
    return dwError;    
}
DWORD USB20Device::ResetEndpoint(DWORD dwEndpoint )
{
    DWORD dwError = ERROR_INVALID_PARAMETER;
    SETFNAME();
    FUNCTION_ENTER_MSG();
    USB20Endpoint *pEndpoint =  ObjectIndex(dwEndpoint);
    if (pEndpoint) {
        dwError = pEndpoint->ResetEndpoint();
        pEndpoint->DeRef();
    }
    FUNCTION_LEAVE_MSG();
    return dwError;    
    
}
DWORD USB20Device::IsEndpointHalted( DWORD dwEndpoint, PBOOL pfHalted )
{
    DWORD dwError = ERROR_INVALID_PARAMETER;
    SETFNAME();
    FUNCTION_ENTER_MSG();
    USB20Endpoint *pEndpoint =  ObjectIndex(dwEndpoint);
    if (pEndpoint) {
        dwError = pEndpoint->IsEndpointHalted(pfHalted);
        pEndpoint->DeRef();
    }
    FUNCTION_LEAVE_MSG();
    return dwError;    
}
DWORD USB20Device::IssueTransfer(DWORD  dwEndpoint,PSTransfer pTransfer )
{
    DWORD dwError = ERROR_INVALID_PARAMETER;
    SETFNAME();
    FUNCTION_ENTER_MSG();
    USB20Endpoint *pEndpoint =  ObjectIndex(dwEndpoint);
    if (pEndpoint) {
        dwError = pEndpoint->IssueTransfer(pTransfer);
        pEndpoint->DeRef();
    }
    FUNCTION_LEAVE_MSG();
    return dwError;    
}
DWORD USB20Device::AbortTransfer(DWORD dwEndpoint, PSTransfer pTransfer)
{
    DWORD dwError = ERROR_INVALID_PARAMETER;
    SETFNAME();
    FUNCTION_ENTER_MSG();
    if (pTransfer) {
        USB20Endpoint *pEndpoint =  ObjectIndex(dwEndpoint);
        if (pEndpoint) {
            dwError = pEndpoint->AbortTransfer(pTransfer);
            pEndpoint->DeRef();
        }
    }
    FUNCTION_LEAVE_MSG();
    return dwError;    
}
    
//  Endpoint Zero Special
DWORD USB20Device::SendControlStatusHandshake(DWORD dwEndpoint)
{
    DWORD dwError = ERROR_INVALID_PARAMETER;
    SETFNAME();
    FUNCTION_ENTER_MSG();
    USB20Endpoint *pEndpoint =  ObjectIndex(0);
    if (pEndpoint) {
        dwError = pEndpoint->SendControlStatusHandshake();
        pEndpoint->DeRef();
    }
    FUNCTION_LEAVE_MSG();
    return dwError;    
}

//  Device Function.
DWORD USB20Device::Start()
{
    SETFNAME();
    FUNCTION_ENTER_MSG();
    DWORD dwReturn = ERROR_SUCCESS;
    Lock();
    //ASSERT(m_pvMddContext==NULL);
    m_dwCurConfigure = MAXDWORD;
    m_dwCurInterface = MAXDWORD;
    // Enable Device Interrupt.
    
	//if(m_pRegsBase->u2dotgusr&XLLP_U2DOTGUSR_VV)
	{ /// When UDE =1, system halt when entry D0CS

        XllpU2DEnableInterrupt(GetXllpHandle(), U2D_INT_RESET, (XLLP_U2D_EP_INTERRUPT_TYPE_T)0);
        XllpU2DEnableInterrupt(GetXllpHandle(), U2D_INT_RESUME, (XLLP_U2D_EP_INTERRUPT_TYPE_T)0);
        XllpU2DEnableInterrupt(GetXllpHandle(), U2D_INT_SUSPEND, (XLLP_U2D_EP_INTERRUPT_TYPE_T)0);  
        XllpU2DEnableInterrupt(GetXllpHandle(), U2D_INT_CONFIG, (XLLP_U2D_EP_INTERRUPT_TYPE_T)0);   

        XllpU2DEnable(GetXllpHandle());
        
        //To second connection.
        m_pRegsBase->u2dctrl&=~XLLP_U2DCR_ADD; //Clear ADD;
        m_pRegsBase->u2dctrl|=XLLP_U2DCR_UDR;
        
        m_fIsCableAttached = TRUE;
    }

    Unlock();
    FUNCTION_LEAVE_MSG();
    return dwReturn;
}

DWORD USB20Device::Stop()
{
    unsigned int temp;

    SETFNAME();
    FUNCTION_ENTER_MSG();
    Lock();

    //ASSERT(m_pvMddContext!=NULL);
    //m_pvMddContext = NULL;
    //Disable Device Interrupt.
   
    m_pRegsBase->u2dicr = 0;

    m_pRegsBase->u2dicr2 = 0;

    m_pRegsBase->u2dctrl |=XLLP_U2DCR_ADD;
    temp = m_pRegsBase->u2dctrl;

    m_pRegsBase->u2dctrl = 0; //disable U2D
    temp = m_pRegsBase->u2dctrl;

	ResetEndpoint(0);    

    Unlock();
    FUNCTION_LEAVE_MSG();
    return ERROR_SUCCESS;
    
}
DWORD  USB20Device::SetAddress( BYTE  bAddress )
{
    // Do we need handle this? NO?
    return ERROR_SUCCESS;
}

//Force U2D out of suspend
void  USB20Device::Initiate_RemoteWakeup()
{
    if(!(m_pRegsBase->u2dctrl & XLLP_U2DCR_DWRE))
        return;
    else
        m_pRegsBase->u2dctrl |= XLLP_U2DCR_UDR ;
}

void USB20Device::PowerMgr(BOOL bOff)
{
    Lock();
    if (bOff)
    {
	    Stop();
    }
    else 
    {
    	m_fResumeOccurred = TRUE;
		ReInit();
    }
    Unlock();
}

void USB20Device::PowerDown() 
{
    if (m_CurPowerState == PwrDeviceUnspecified) {
        PowerMgr(TRUE) ;
    }
}
void USB20Device::PowerUp()
{
    m_fResumeOccurred = TRUE;
    if (m_CurPowerState == PwrDeviceUnspecified) {
        PowerMgr(FALSE) ;
    }
}
void USB20Device::SetPowerState( CEDEVICE_POWER_STATE cpsNew )
{
    SETFNAME();

    // Adjust cpsNew.
    if (cpsNew != m_CurPowerState ) {
        if (cpsNew == D1 || cpsNew == D2) {
            // D1 and D2 are not supported.
            cpsNew = D0;
        }
        else if (m_CurPowerState== D4) {
            // D4 can only go to D0.
            cpsNew = D0;
        }
    }
    if (cpsNew != m_CurPowerState ) {
        BOOL bBusSucceed = FALSE;
        DEBUGMSG(ZONE_FUNCTION, (_T("%s Going from D%u to D%u\r\n"), pszFname, m_CurPowerState , cpsNew));
        if ( (cpsNew < m_CurPowerState) && m_hParent) {
            bBusSucceed = SetDevicePowerState(m_hParent, cpsNew, NULL);
            if (bBusSucceed) {
                PowerMgr(FALSE);
            }
        }

        switch (cpsNew) {
        case D0:
            KernelIoControl(IOCTL_HAL_DISABLE_WAKE, &m_dwSysIntr,sizeof(m_dwSysIntr), NULL, 0, NULL);
            if (m_fResumeOccurred)
            {
               m_fForceResume = FALSE;
               //ReInit();
#ifdef ENABLE_SERIAL_AUTO_CONNECTION
               if (m_fIsCableAttached) {
                  RETAILMSG(1, (TEXT("----->USB20Device::SetPowerState - Attach\r\n")));
                  m_fIsCableAttached = FALSE;
                  SetEvent(m_hISTEvent);
               }
               else {
                  RETAILMSG(1, (TEXT("----->USB20Device::SetPowerState - Detach\r\n")));
                  m_fResumeOccurred = FALSE;
               }
#endif
            };
            break;
        case D3:
            KernelIoControl(IOCTL_HAL_ENABLE_WAKE, &m_dwSysIntr,  sizeof(m_dwSysIntr), NULL, 0, NULL);
            break;
        case D4:
            KernelIoControl(IOCTL_HAL_DISABLE_WAKE, &m_dwSysIntr,  sizeof(m_dwSysIntr), NULL, 0, NULL);
            break;
        }
        if ( (cpsNew > m_CurPowerState ) && m_hParent  ) {
            bBusSucceed = SetDevicePowerState(m_hParent, cpsNew, NULL);
            if (bBusSucceed && cpsNew == D4) {
                PowerMgr(TRUE);
            }
        }
        m_CurPowerState = cpsNew;
    }
}
BOOL USB20Device::InitMFPRM()
{

    BOOL bFirstInit=FALSE;

    m_MfpRMDHandle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
            0, XLLP_MFP_RM_DB_SIZE, MFPRMDB_SHARED_FILENAME );

    if(m_MfpRMDHandle == NULL )
    {
        NKDbgPrintfW(TEXT("[USB20] Fail to CreateFileMapping(MFPRMDB_SHARED_FILENAME)! \r\n"));;
        return FALSE;
    }

    if (ERROR_ALREADY_EXISTS != GetLastError()) 
    {
            // The first initialization of this memory-mapped file.
            DEBUGMSG(ZONE_INIT, (TEXT("[USB20] First call of CreateFileMapping(MFPRMDB_SHARED_FILENAME)! \r\n")));      

            bFirstInit = TRUE;      

    }else 
    {
            // Memory-mapped file already existed.
            DEBUGMSG(ZONE_INIT, (TEXT("USB20 Sequent call of CreateFileMapping(MFPRMDB_SHARED_FILENAME)! \r\n")));

            bFirstInit = FALSE;
    }

    m_pMfpRMDb = (P_XLLP_MFP_RM_DB_ID_T) MapViewOfFile(m_MfpRMDHandle, FILE_MAP_ALL_ACCESS, 0, 0, 0 );
        
    if (NULL == m_pMfpRMDb )
    {
          NKDbgPrintfW(TEXT("[USB20] Fail to MapViewOfFile()!\r\n"));
          return FALSE; //if failed
    }

    if (TRUE == bFirstInit) 
    {
            // Need to Initialize RM    
        if (XLLP_STATUS_SUCCESS != XllpMfpResourceManagerInit(m_pMfpRMDb)) 
        {
            NKDbgPrintfW(TEXT("[USB20] Fail to XllpMfpResourceManagerInit()!\r\n"));
            return FALSE; //if failed
        }
    }
    return TRUE;
}
DWORD USB20Device::IOControl( IOCTL_SOURCE source, DWORD dwCode, PBYTE  pbIn, DWORD cbIn, PBYTE pbOut, DWORD cbOut,PDWORD  pcbActualOut )
{
    SETFNAME();
    FUNCTION_ENTER_MSG();

    DWORD dwRet = ERROR_INVALID_PARAMETER;

    switch (dwCode) 
    {
	case IOCTL_UFN_RESET_CONTROLLER:
		ReInit();		
		RETAILMSG(1,(_T("USB IoControl Reset\r\n")));
        dwRet = ERROR_SUCCESS;

		break;

	case IOCTL_UFN_STOP_CONTROLLER:
		Stop();
		DeviceNotification( UFN_MSG_BUS_EVENTS, UFN_DETACH);
		RETAILMSG(1,(_T("USB IoControl Stop\r\n")));
		dwRet = ERROR_SUCCESS;
		break;


    case IOCTL_UFN_GET_PDD_INFO:
        if ( source != BUS_IOCTL || pbOut == NULL || cbOut != sizeof(UFN_PDD_INFO) ) {
            break;
        }

    //To support USB DMA. Tell up layer stack that hardware support DMA transfer. So up layer can alloc DMA buffer. 
        if (CeSafeCopyMemory(pbOut, &m_PDDInfo, sizeof(UFN_PDD_INFO))) 
        {

            dwRet = ERROR_SUCCESS;
            //*pcbActualOut = sizeof(UFN_PDD_INFO);
        }
        // Not currently supported.
        break;

    case IOCTL_BUS_GET_POWER_STATE:
        if (source == MDD_IOCTL) {
            PREFAST_DEBUGCHK(pbIn);
            DEBUGCHK(cbIn == sizeof(CE_BUS_POWER_STATE));

            PCE_BUS_POWER_STATE pCePowerState = (PCE_BUS_POWER_STATE) pbIn;
            PREFAST_DEBUGCHK(pCePowerState->lpceDevicePowerState);

            DEBUGMSG(ZONE_FUNCTION, (_T("%s IOCTL_BUS_GET_POWER_STATE\r\n"), pszFname));

            *pCePowerState->lpceDevicePowerState = m_CurPowerState;

            dwRet = ERROR_SUCCESS;
        }
        break;

    case IOCTL_BUS_SET_POWER_STATE:
        if (source == MDD_IOCTL) {
            PREFAST_DEBUGCHK(pbIn);
            DEBUGCHK(cbIn == sizeof(CE_BUS_POWER_STATE));

            PCE_BUS_POWER_STATE pCePowerState = (PCE_BUS_POWER_STATE) pbIn;

            PREFAST_DEBUGCHK(pCePowerState->lpceDevicePowerState);
            DEBUGCHK(VALID_DX(*pCePowerState->lpceDevicePowerState));

            DEBUGMSG(ZONE_FUNCTION, (_T("%s IOCTL_BUS_GET_POWER_STATE(D%u)\r\n"), pszFname, *pCePowerState->lpceDevicePowerState));
            SetPowerState( *pCePowerState->lpceDevicePowerState );
            dwRet = ERROR_SUCCESS;
        }
        break;
    }
    FUNCTION_LEAVE_MSG();
    return dwRet;
}


#ifdef DEBUG
const DWORD cISTTimeOut = 2000;
#else
const DWORD cISTTimeOut = INFINITE ;
#endif

DWORD USB20Device::ThreadRun()
{
    SETFNAME();
    FUNCTION_ENTER_MSG();

    while(!IsAPIReady(SH_SHELL))
    {
        Sleep(1000);
    }

    while (!m_bTerminated && m_hISTEvent!=NULL) 
    {

        if ( WaitForSingleObject(m_hISTEvent,cISTTimeOut) != WAIT_OBJECT_0) 
        {

            DEBUGMSG(ZONE_FUNCTION, (_T("%s : Interrupt Time out dwIntrStatus=0x%x dwIntrCtrl=0x%x\r\n"),pszFname,
                m_pRegsBase->u2disr,m_pRegsBase->u2dicr  ));
             
            DEBUGMSG(ZONE_FUNCTION, (_T("%s : ControlRegister() =0x%x "),pszFname,
                m_pRegsBase->u2dcr ));
        
            if (m_fIsCableAttached != IsCableAttached()) 
            {
                m_fIsCableAttached = IsCableAttached();
                if (m_fIsCableAttached) {
                    //DEBUGMSG(ZONE_FUNCTION, (_T("%s : Attach Detected\r\n"),pszFname));
                    ReInit();
                }
                else {
                    //DEBUGMSG(ZONE_FUNCTION, (_T("%s : Detach Detected\r\n"),pszFname));
                    DeviceNotification( UFN_MSG_BUS_EVENTS, UFN_DETACH);
                }
            }
            continue;
        }

        DWORD dwIntr0Status = m_pRegsBase->u2disr ;
        
        m_pRegsBase->u2disr =  dwIntr0Status & (~(0x1U<<U2D_INT_CONFIG)); //clear all interrupt except CC interrupt

        DEBUGMSG(ZONE_FUNCTION, (_T("%s : USB20Device dwIntr0Status 0x%x\r\n "), pszFname, dwIntr0Status ));

#ifdef ENABLE_SERIAL_AUTO_CONNECTION
        if (m_fResumeOccurred)
        {
           m_fResumeOccurred = FALSE;
           m_fIsCableAttached = FALSE;
           DeviceNotification( UFN_MSG_BUS_EVENTS, UFN_DETACH);

		   WriteULPIReg(0xb, (0x1<<1)|(0x1<<2));
           Sleep(1000);
           WriteULPIReg(0xc, (0x1<<1)|(0x1<<2));

           m_fForceResume = TRUE;
           InterruptDone(m_dwSysIntr);
           continue;
        };
#endif

//		RETAILMSG(1, (_T("USB20Device dwIntr0Status 0x%x\r\n "), dwIntr0Status ));

        DWORD dwIntr2Status = m_pRegsBase->u2disr2 ;
        m_pRegsBase->u2disr2 =  dwIntr2Status; //clear all interrupt

//        DEBUGMSG(ZONE_FUNCTION, (_T("%s : USB20Device dwIntr0Status 0x%x\r\n "), pszFname, dwIntr0Status ));

        DWORD otgisr=m_pRegsBase->u2dotgisr;
        m_pRegsBase->u2dotgisr= XLLP_U2DOTGICR_IESF;//clear Set Feature IRQ only;


        if( otgisr&XLLP_U2DOTGICR_IESF)
        {
            USB_DEVICE_REQUEST udr;

            if (m_pRegsBase->u2dotgcr&XLLP_U2DOTGCR_BHNP) 
            { // Host Set HNP Feature.
                DEBUGMSG(ZONE_FUNCTION, (_T("%s : BHNP Detected\r\n"),pszFname));
                udr.bmRequestType = USB_REQUEST_FOR_DEVICE;
                udr.bRequest = USB_REQUEST_SET_FEATURE ;
                udr.wValue =  USB_FEATURE_B_HNP_ENABLE;
                udr.wIndex =  0 ;
                udr.wLength =0;

                DeviceNotification( UFN_MSG_SETUP_PACKET,(DWORD) &udr);
            }
            if (m_pRegsBase->u2dotgcr&XLLP_U2DOTGCR_AHNP)
            {// Host Set HNP Support.
                DEBUGMSG(ZONE_FUNCTION, (_T("%s : AHNP Detected\r\n"),pszFname));
                udr.bmRequestType = USB_REQUEST_FOR_DEVICE;
                    udr.bRequest = USB_REQUEST_SET_FEATURE ;
                udr.wValue =  USB_FEATURE_A_HNP_SUPPORT;
                udr.wIndex =  0 ;
                udr.wLength =0;
                
                DeviceNotification( UFN_MSG_SETUP_PACKET,(DWORD) &udr);
            }
            if (m_pRegsBase->u2dotgcr&XLLP_U2DOTGCR_AALTHNP)
            { // Host Set Alter HNP Support.
                DEBUGMSG(ZONE_FUNCTION, (_T("%s : AALTHNP Detected\r\n"),pszFname));
                udr.bmRequestType = USB_REQUEST_FOR_DEVICE;
                udr.bRequest = USB_REQUEST_SET_FEATURE ;
                udr.wValue =  USB_FEATURE_A_ALT_HNP_SUPPORT;
                udr.wIndex =  0 ;
                udr.wLength =0;
                
                DeviceNotification(UFN_MSG_SETUP_PACKET,(DWORD) &udr);
            }
        }
        // Check Cable in any Interrupt.
        if ((m_fIsCableAttached != IsCableAttached()) && (!m_fForceResume)) 
        {
            m_fIsCableAttached = IsCableAttached();

            if (m_fIsCableAttached) {
                //DEBUGMSG(ZONE_FUNCTION, (_T("%s : Attach Detected\r\n"),pszFname));
                ReInit();
            }
            else {
                //DEBUGMSG(ZONE_FUNCTION, (_T("%s : Detach Detected\r\n"),pszFname));
                DeviceNotification( UFN_MSG_BUS_EVENTS, UFN_DETACH);
            }
        }
        
        // Processing Device Interrupt 
        if ( dwIntr0Status & (0x1U<<U2D_INT_CONFIG)) 
        { // Setup Config or Setup Interface has been received.

            USB_DEVICE_REQUEST udr;

            XLLP_UINT32_T ulValue = m_pRegsBase->u2dctrl;

            XllpU2DConfigChangeCallback(GetXllpHandle());

            
            m_pRegsBase->u2dctrl = XLLP_U2DCR_UDE | XLLP_U2DCR_CC| XLLP_U2DCR_SMAC | XLLP_U2DCR_SPEOREN;

            DEBUGMSG(ZONE_TRANSFER, (_T("%s : Setup Configuration and Interface received UDCCR=0x%x.\r\n"),pszFname,m_pRegsBase->u2dctrl));
            DEBUGMSG(ZONE_TRANSFER, (_T("%s : U2DSRA =0x%x. U2DSRB =0x%x.\r\n"),pszFname, m_pRegsBase->u2dcsr[1],m_pRegsBase->u2dcsr[2]));

            XLLP_UINT32_T ACN = (ulValue&XLLP_U2DCR_ACN_MASK) >> XLLP_U2DCR_ACN_SHIFT;
            XLLP_UINT32_T AIN = (ulValue&XLLP_U2DCR_AIN_MASK) >> XLLP_U2DCR_AIN_SHIFT;
            XLLP_UINT32_T AAISN = (ulValue&XLLP_U2DCR_AAISN_MASK) >> XLLP_U2DCR_AAISN_SHIFT;
            
           
            // COnfiguration has changed.
            for (DWORD dwIndex=0; dwIndex<XLLP_U2D_USB_MAX_EP_NUM; dwIndex++)
            {
                USB20Endpoint *pEndpoint = ObjectIndex(dwIndex);
                if (pEndpoint!=NULL)  
                {
                    pEndpoint->ReInit();
                    pEndpoint->DeRef();
                }
            }
            udr.bmRequestType = USB_REQUEST_FOR_DEVICE;
            udr.bRequest = USB_REQUEST_SET_CONFIGURATION;
            udr.wValue = (USHORT) ACN;
            udr.wIndex =  0;
            udr.wLength =0;
            m_dwCurConfigure = ACN ;
            DeviceNotification( UFN_MSG_SETUP_PACKET,(DWORD) &udr);
           
            
            if (AIN*0x100 + AAISN != m_dwCurInterface) {
                udr.bmRequestType = USB_REQUEST_FOR_DEVICE;
                udr.bRequest = USB_REQUEST_SET_INTERFACE;
                udr.wValue = (USHORT)AAISN;
                udr.wIndex = (USHORT)AIN;
                udr.wLength= 0;
                m_dwCurInterface = AIN*0x100 + AAISN ;
                // We can not do this because MDD will stall the endpoint.
                //DeviceNotification( UFN_MSG_SETUP_PACKET,(DWORD) &udr);
            }
            m_pRegsBase->u2dctrl =(1u<<27)| XLLP_U2DCR_UDE | XLLP_U2DCR_CC| XLLP_U2DCR_SMAC;
            while(m_pRegsBase->u2dctrl & XLLP_U2DCR_SMAC);
            m_pRegsBase->u2disr = 0x1U<<U2D_INT_CONFIG;
                
        }

        if ( dwIntr0Status & (0x1U<<U2D_INT_RESUME)) 
        { 
            // Resume Detected
            DEBUGMSG(ZONE_FUNCTION, (_T("%s : Resume Detected\r\n"),pszFname));

            RETAILMSG(1, (_T("Resume Detected\r\n")));
            DeviceNotification( UFN_MSG_BUS_EVENTS, UFN_RESUME);
            
#ifdef ENABLE_SERIAL_AUTO_CONNECTION
            if (m_fForceResume)
            {
               XLLP_UINT32_T Value = m_pRegsBase->u2dctrl;
               Value &= ~XLLP_U2DCR_UDR;
               m_pRegsBase->u2dctrl = Value;
               
               m_fForceResume = FALSE;
            }
#endif

        }

        if (dwIntr0Status & (0x1U<<U2D_INT_SUSPEND) ) 
        { // Suspend Detected.
            DEBUGMSG(ZONE_FUNCTION, (_T("%s : Suspend Detected\r\n"),pszFname));

            RETAILMSG(1, (_T("Suspend Detected\r\n")));
            DeviceNotification( UFN_MSG_BUS_EVENTS, UFN_SUSPEND);
            
#ifdef ENABLE_SERIAL_AUTO_CONNECTION
            if (m_fForceResume)
            {
               XLLP_UINT32_T Value = m_pRegsBase->u2dctrl;
               Value |= XLLP_U2DCR_UDR;
               m_pRegsBase->u2dctrl = Value;
               
               InterruptDone(m_dwSysIntr);
               continue;
            }
#endif
        }

        DWORD bus = BS_UNKNOWN_SPEED;

        if (dwIntr0Status & (0x1U<<U2D_INT_RESET) ) 
        { // Reset Detected.
            DEBUGMSG(ZONE_FUNCTION, (_T("%s : Reset Detected\r\n"),pszFname));
            // Set DETACH First
            DeviceNotification( UFN_MSG_BUS_EVENTS, UFN_DETACH);
            // Set ATTACH.
            DeviceNotification( UFN_MSG_BUS_EVENTS, UFN_ATTACH);
            // Set Reset
            DeviceNotification( UFN_MSG_BUS_EVENTS, UFN_RESET);
            
            bus= m_pRegsBase->u2dctrl&XLLP_U2DCR_HS? BS_HIGH_SPEED:BS_FULL_SPEED;
            DWORD speedTimeOut = 10;
            while ((bus == BS_FULL_SPEED)&&speedTimeOut)
            {
                Sleep(1);
                speedTimeOut --;
                bus= m_pRegsBase->u2dctrl&XLLP_U2DCR_HS? BS_HIGH_SPEED:BS_FULL_SPEED;
            }
            RETAILMSG(TRUE,(_T("USB Speed at Reset: %s\r\n"), m_busSpeed==BS_HIGH_SPEED?_T("High"):_T("FULL")));
            // This device can support FULL Speed and High Speed.
            DeviceNotification( UFN_MSG_BUS_SPEED, bus);
            m_busSpeed = bus;
            
            // The HW Filters the Set Address ... Fake it here
            DeviceNotification( UFN_MSG_SET_ADDRESS, 0xFF);

         
        }
        
        bus= m_pRegsBase->u2dctrl&XLLP_U2DCR_HS? BS_HIGH_SPEED:BS_FULL_SPEED;
        if (bus != m_busSpeed )
        {
             m_busSpeed=bus;
             if(m_busSpeed!=BS_UNKNOWN_SPEED)
             {
                 DeviceNotification( UFN_MSG_BUS_SPEED, m_busSpeed);
             }
             RETAILMSG(TRUE,(_T("USB Speed: %s\r\n"), m_busSpeed==BS_HIGH_SPEED?_T("High"):_T("FULL")));
        }
        USB20Endpoint *pEndpoint;
        DWORD dwIntrStatusCopy = dwIntr0Status;
        DWORD dwIntrStatusCopy2 = dwIntr2Status;    

        DWORD dwDmaStatusCopy = m_pRegsBase->u2dmaint ;
        for (DWORD dwIndex =0 ; dwIndex < XLLP_U2D_USB_MAX_EP_NUM; dwIndex ++ ) 
        {

            if( dwIndex == U2D_ENDPOINT_H)
                dwIntrStatusCopy=dwIntrStatusCopy2;
            if ( (dwIntrStatusCopy & ( U2D_SHORT_PACKET_COMPL_INT| U2D_PACKET_COMPL_INT| U2D_FIFO_ERROR_INT))!=0
                || (dwDmaStatusCopy & 0x1)
                ) 
            {       
                if ((pEndpoint = ObjectIndex(dwIndex)) != NULL ) 
                {
                    DEBUGMSG(ZONE_TRANSFER, (_T("EP%d IST Status 0x%x data\r\n"), dwIndex,dwIntrStatusCopy));           
                    //if( (!pEndpoint->GetDMAEnable()) ||  (pEndpoint->m_epDesc.bEndpointAddress & 0x80) )
                    {
                        pEndpoint->IST(dwIntrStatusCopy & (U2D_SHORT_PACKET_COMPL_INT| U2D_PACKET_COMPL_INT| U2D_FIFO_ERROR_INT ),dwDmaStatusCopy&0x1);
                    }
                    pEndpoint->DeRef();
                }
            }
            dwIntrStatusCopy >>=3;
            dwDmaStatusCopy>>=1;
        }

        InterruptDone(m_dwSysIntr);


    }
    FUNCTION_LEAVE_MSG();
    return 1;
}

/// Deinit PDD
/// Delete PDD Object 
/// @return ERROR_SUCCESS       Success 
///         Other               Fail
DWORD
WINAPI
UfnPdd_Deinit(
    PVOID pvPddContext
    )
{
    if (pvPddContext) {
        delete ((USB20Device *)pvPddContext);
        return ERROR_SUCCESS ;
    }
    else
        return ERROR_INVALID_PARAMETER;
}

/// Is Coniguration supported
/// Do Nothing
/// @return ERROR_SUCCESS       Success 
DWORD 
WINAPI 
UfnPdd_IsConfigurationSupportable(
    PVOID                       pvPddContext,
    UFN_BUS_SPEED               Speed,
    PUFN_CONFIGURATION          pConfiguration
    )
{
    return ERROR_SUCCESS;
}


/// Is Endpoint Support
/// USB Funcation driver PDD Interface function
/// @param  pvPddContext        [IN]PDD context
/// @param  dwEndpoint          [IN]Endpoint Number
/// @param  Speed               [IN]Speed (High, Full, Low)
/// @param  pEndpointDesc       [IN] Endpoint Descriptor
/// @param  bConfigurationValue [IN] Configuration Number
/// @param  bInterfaceNumber        [IN]Interface number
/// @param  bAlternateSetting       [IN]Alternate setting
/// @return ERROR_SUCCESS       Success 
///         Other               Fail
DWORD
WINAPI
UfnPdd_IsEndpointSupportable(
    PVOID                       pvPddContext,
    DWORD                       dwEndpoint,
    UFN_BUS_SPEED               Speed,
    PUSB_ENDPOINT_DESCRIPTOR    pEndpointDesc,
    BYTE                        bConfigurationValue,
    BYTE                        bInterfaceNumber,
    BYTE                        bAlternateSetting
    )
{
    DWORD dwError = ERROR_INVALID_PARAMETER;
    if (pvPddContext) {
        dwError =((USB20Device *)pvPddContext)->IsEndpointSupportable( dwEndpoint, Speed, pEndpointDesc ,bConfigurationValue,bInterfaceNumber,bAlternateSetting );
    };
    return dwError;
}


/// Init Endpoint
/// USB Funcation driver PDD Interface function
/// @param  pvPddContext        [IN]PDD context
/// @param  dwEndpoint          [IN]Endpoint Number
/// @param  Speed               [IN]Speed (High, Full, Low)
/// @param  pEndpointDesc       [IN] Endpoint Descriptor
/// @param  pvReserved          [IN] Resevered
/// @param  bConfigurationValue [IN] Configuration Number
/// @param  bInterfaceNumber        [IN]Interface number
/// @param  bAlternateSetting       [IN]Alternate setting
/// @return ERROR_SUCCESS       Success 
///         Other               Fail
DWORD
WINAPI
UfnPdd_InitEndpoint(
    PVOID                       pvPddContext,
    DWORD                       dwEndpoint,
    UFN_BUS_SPEED               Speed,
    PUSB_ENDPOINT_DESCRIPTOR    pEndpointDesc,
    PVOID                       pvReserved,
    BYTE                        bConfigurationValue,
    BYTE                        bInterfaceNumber,
    BYTE                        bAlternateSetting
    )
{
    DWORD dwError = ERROR_INVALID_PARAMETER;
    if (pvPddContext) {
        dwError =((USB20Device *)pvPddContext)->InitEndpoint( dwEndpoint, Speed, pEndpointDesc, bConfigurationValue,bInterfaceNumber,bAlternateSetting );
    };
    return dwError;
}

/// Register a Device
/// USB Funcation driver PDD Interface function
/// Do Nothing
/// @return ERROR_SUCCESS       Success 
DWORD
WINAPI
UfnPdd_RegisterDevice(
    PVOID                           pvPddContext,
    PCUSB_DEVICE_DESCRIPTOR         pHighSpeedDeviceDesc,
    PCUFN_CONFIGURATION             pHighSpeedConfig,
    PCUSB_CONFIGURATION_DESCRIPTOR  pHighSpeedConfigDesc,
    PCUSB_DEVICE_DESCRIPTOR         pFullSpeedDeviceDesc,
    PCUFN_CONFIGURATION             pFullSpeedConfig,
    PCUSB_CONFIGURATION_DESCRIPTOR  pFullSpeedConfigDesc,
    PCUFN_STRING_SET                pStringSets,
    DWORD                           cStringSets
    )
{
    return ERROR_SUCCESS;
}

/// Deregister a Device
/// USB Funcation driver PDD Interface function
/// Do Nothing
/// @return ERROR_SUCCESS       Success 
DWORD
WINAPI
UfnPdd_DeregisterDevice(
    PVOID   pvPddContext
    )
{
    if (pvPddContext) {
        ((USB20Device *)pvPddContext)->DeleteAllEndpoint();
    };
    return ERROR_SUCCESS;
}

/// Start PDD Device
/// USB Funcation driver PDD Interface function
/// @param  pvPddContext        [IN]PDD context
/// @return ERROR_SUCCESS       Success 
///         Other               Fail
DWORD
WINAPI
UfnPdd_Start(
    PVOID        pvPddContext
    )
{
    DWORD dwError = ERROR_INVALID_PARAMETER;
    if (pvPddContext) {
        dwError =((USB20Device *)pvPddContext)->Start();
    };
    return dwError;
}


/// Stop PDD Device
/// USB Funcation driver PDD Interface function
/// @param  pvPddContext        [IN]PDD context
/// @return ERROR_SUCCESS       Success 
///         Other               Fail
DWORD
WINAPI
UfnPdd_Stop(
    PVOID        pvPddContext
    )
{
    DWORD dwError = ERROR_INVALID_PARAMETER;

    if (pvPddContext) {
        dwError =((USB20Device *)pvPddContext)->Stop();
    };

    return dwError;
}

/// Issue Transfer 
/// USB Funcation driver PDD Interface function
/// @param  pvPddContext        [IN]PDD  context
/// @param  dwEndpoint          [IN]Endpoint Number
/// @param  pTransfer           [IN]Transfer data
/// @return ERROR_SUCCESS       Success 
///         Other               Fail
DWORD
WINAPI
UfnPdd_IssueTransfer(
    PVOID  pvPddContext,
    DWORD  dwEndpoint,
    PSTransfer pTransfer
    )
{
    DWORD dwError = ERROR_INVALID_PARAMETER;

    if (pvPddContext) {
        dwError =((USB20Device *)pvPddContext)->IssueTransfer(dwEndpoint,pTransfer);
    };

    return dwError;
}

/// Abort Transfer 
/// USB Funcation driver PDD Interface function
/// @param  pvPddContext        [IN]PDD  context
/// @param  dwEndpoint          [IN]Endpoint Number
/// @param  pTransfer           [IN]Transfer data
/// @return ERROR_SUCCESS       Success 
///         Other               Fail
DWORD
WINAPI
UfnPdd_AbortTransfer(
    PVOID           pvPddContext,
    DWORD           dwEndpoint,
    PSTransfer      pTransfer
    )
{
    DWORD dwError = ERROR_INVALID_PARAMETER;
    if (pvPddContext) {
        dwError =((USB20Device *)pvPddContext)->AbortTransfer(dwEndpoint, pTransfer);
    };

    return dwError;
}

/// De init Endpoint
/// USB Funcation driver PDD Interface function
/// @param  pvPddContext        [IN]PDD  context
/// @param  dwEndpoint          [IN]Endpoint Number
/// @return ERROR_SUCCESS       Success 
///         Other               Fail
DWORD
WINAPI
UfnPdd_DeinitEndpoint(
    PVOID           pvPddContext,
    DWORD           dwEndpoint
    )
{
    DWORD dwError = ERROR_INVALID_PARAMETER;
    if (pvPddContext) {
        dwError =((USB20Device *)pvPddContext)->DeinitEndpoint(dwEndpoint);
    };

    return dwError;
}


/// Stall Endpoint
/// USB Funcation driver PDD Interface function
/// @param  pvPddContext        [IN]PDD  context
/// @param  dwEndpoint          [IN]Endpoint Number
/// @return ERROR_SUCCESS       Success 
///         Other               Fail
DWORD
WINAPI
UfnPdd_StallEndpoint(
    PVOID           pvPddContext,
    DWORD           dwEndpoint
    )
{
    DWORD dwError = ERROR_INVALID_PARAMETER;

    if (pvPddContext) {
        dwError =((USB20Device *)pvPddContext)->StallEndpoint(dwEndpoint);
    };

    return dwError;
}


/// Clear Endpoint stall status
/// USB Funcation driver PDD Interface function
/// @param  pvPddContext        [IN]PDD  context
/// @param  dwEndpoint          [IN]Endpoint Number
/// @return ERROR_SUCCESS       Success 
///         Other               Fail
DWORD
WINAPI
UfnPdd_ClearEndpointStall(
    PVOID           pvPddContext,
    DWORD           dwEndpoint
    )
{
    DWORD dwError = ERROR_INVALID_PARAMETER;
    if (pvPddContext) {
        dwError =((USB20Device *)pvPddContext)->ClearEndpointStall(dwEndpoint);
    };

    return dwError;
}


/// Send Control Endpoint Hand shake
/// USB Funcation driver PDD Interface function
/// @param  pvPddContext        [IN]PDD  context
/// @param  dwEndpoint          [IN]Endpoint Number
/// @return ERROR_SUCCESS       Success 
///         Other               Fail
DWORD
WINAPI
UfnPdd_SendControlStatusHandshake(
    PVOID           pvPddContext,
    DWORD           dwEndpoint
    )
{
    DWORD dwError = ERROR_INVALID_PARAMETER;
    if (pvPddContext) {
        dwError =((USB20Device *)pvPddContext)->SendControlStatusHandshake(dwEndpoint);
    };

    return dwError;
}

/// Send Control Endpoint Hand shake
/// USB Funcation driver PDD Interface function
/// @param  pvPddContext        [IN]PDD  context
/// @param  dwEndpoint          [IN]Endpoint Number
/// @return ERROR_SUCCESS       Success 
///         Other               Fail
DWORD
WINAPI
UfnPdd_SetAddress(
    PVOID pvPddContext,
    BYTE  bAddress
    )
{
    DWORD dwError = ERROR_INVALID_PARAMETER;
    if (pvPddContext) {
        dwError =((USB20Device *)pvPddContext)->SetAddress(bAddress);
    };

    return dwError;

}


/// is Endpoint halt
/// USB Funcation driver PDD Interface function
/// @param  pvPddContext        [IN]PDD  context
/// @param  dwEndpoint          [IN]Endpoint Number
/// @param  pfHalted            [OUT]halt status
/// @return ERROR_SUCCESS       Success 
///         Other               Fail
DWORD
WINAPI
UfnPdd_IsEndpointHalted(
    PVOID pvPddContext,
    DWORD dwEndpoint,
    PBOOL pfHalted
    )
{
    DWORD dwError = ERROR_INVALID_PARAMETER;

    if (pvPddContext) {
        dwError =((USB20Device *)pvPddContext)->IsEndpointHalted(dwEndpoint,pfHalted);
    };

    return dwError;
}

/// Init Remote Wake up
/// USB Funcation driver PDD Interface function
/// Do nothing
/// @param  pvPddContext        [IN]PDD  context
/// @return ERROR_SUCCESS       Success 
DWORD
WINAPI
UfnPdd_InitiateRemoteWakeup(
    PVOID pvPddContext
    )
{
        
    if (pvPddContext) {
        ((USB20Device *)pvPddContext)->Initiate_RemoteWakeup();
    }    
    return ERROR_SUCCESS;
}

/// Call this when system suspend
/// USB Funcation driver PDD Interface function
/// @param  pvPddContext        [IN]PDD  context
void
WINAPI
UfnPdd_PowerDown(
    PVOID pvPddContext
    )
{

    if (pvPddContext) {
        ((USB20Device *)pvPddContext)->PowerDown();
    };

}

/// Call this when system resume
/// USB Funcation driver PDD Interface function
/// @param  pvPddContext        [IN]PDD  context
void
WINAPI
UfnPdd_PowerUp(
    PVOID pvPddContext
    )
{
    if (pvPddContext) {
        ((USB20Device *)pvPddContext)->PowerUp();
    };
}

/// IO Control
/// USB Funcation driver PDD Interface function
/// @param  pvPddContext        [IN]PDD  context
/// @remarks IOCTLs with a Function value between 0x200 and 0x2FF are reserved 
///    for the OEM.
DWORD
WINAPI
UfnPdd_IOControl(
    PVOID           pvPddContext,
    IOCTL_SOURCE    source,
    DWORD           dwCode,
    PBYTE           pbInBuf,
    DWORD           cbInBuf,
    PBYTE           pbOutBuf,
    DWORD           cbOutBuf,
    PDWORD          pcbActualOutBuf
    )
{
    DWORD dwError = ERROR_INVALID_PARAMETER;

    if (pvPddContext) {
        dwError =((USB20Device *)pvPddContext)->IOControl(source, dwCode, pbInBuf, cbInBuf, pbOutBuf,  cbOutBuf, pcbActualOutBuf);
    };


    return dwError;
}

/// PDD Init funtion
/// USB Funcation driver PDD Interface function
///
/// @param  pszActiveKey        [IN]Active Key for the interface driver
/// @param  pvMddContext        [IN]MDD context
/// @param  pPddInterfaceInfo   [OUT] PDD Info
/// @return ERROR_SUCCESS       Success 
///         Other               Fail
///
/// @remarks  This function is PDD entry point. Create USB PDD object and return pddinterfaceinfo
extern "C"
DWORD
WINAPI
UfnPdd_Init(
    LPCTSTR                     pszActiveKey,
    PVOID                       pvMddContext,
    PUFN_MDD_INTERFACE_INFO     pMddInterfaceInfo,
    PUFN_PDD_INTERFACE_INFO     pPddInterfaceInfo
    )
{

    static const UFN_PDD_INTERFACE_INFO sc_PddInterfaceInfo = {
        UFN_PDD_INTERFACE_VERSION,
        UFN_PDD_CAPS_SUPPORTS_FULL_SPEED|UFN_PDD_CAPS_SUPPORTS_HIGH_SPEED,
        XLLP_U2D_USB_MAX_EP_NUM,
        NULL,
        
        &UfnPdd_Deinit,
        &UfnPdd_IsConfigurationSupportable,
        &UfnPdd_IsEndpointSupportable,
        &UfnPdd_InitEndpoint,
        &UfnPdd_RegisterDevice,
        &UfnPdd_DeregisterDevice,
        &UfnPdd_Start,
        &UfnPdd_Stop,
        &UfnPdd_IssueTransfer,
        &UfnPdd_AbortTransfer,
        &UfnPdd_DeinitEndpoint,
        &UfnPdd_StallEndpoint,
        &UfnPdd_ClearEndpointStall,
        &UfnPdd_SendControlStatusHandshake,
        &UfnPdd_SetAddress,
        &UfnPdd_IsEndpointHalted,
        &UfnPdd_InitiateRemoteWakeup,
        &UfnPdd_PowerDown,
        &UfnPdd_PowerUp,
        &UfnPdd_IOControl,
    };

    memcpy(pPddInterfaceInfo, &sc_PddInterfaceInfo, sizeof(sc_PddInterfaceInfo));

    USB20Device * pDevice = CreateUSB20Device(pszActiveKey );
    if (pDevice && pDevice->Init( pvMddContext, pMddInterfaceInfo, pPddInterfaceInfo)==ERROR_SUCCESS) {
        return ERROR_SUCCESS;
    }
    
    if (pDevice!=NULL)
        delete pDevice;

    return ERROR_INVALID_PARAMETER;
}

/// PDD DllEtry
/// Do onthing and return TRUE
extern "C"
BOOL
UfnPdd_DllEntry(
    HANDLE hDllHandle,
    DWORD  dwReason, 
    LPVOID lpReserved
    )
{
    return TRUE; // Nothing to do.
}


#ifdef DEBUG
UFN_GENERATE_DPCURSETTINGS(UFN_DEFAULT_DPCURSETTINGS_NAME, 
    _T(""), _T("DMAIN"), _T("DMAOUT"),_T("DATA"),
    DBG_ERROR | DBG_WARNING|ZONE_TRANSFER);
#endif




